package com.aizuda.boot.modules.business.negotiation.service.impl;

import com.aizuda.boot.modules.business.contract.dto.SingleResponse;
import com.aizuda.boot.modules.business.contract.dto.UserInfo;
import com.aizuda.boot.modules.business.contract.entity.ContractEntity;
import com.aizuda.boot.modules.business.contract.entity.ContractFieldEntity;
import com.aizuda.boot.modules.business.contract.entity.ContractFieldValueEntity;
import com.aizuda.boot.modules.business.contract.entity.dto.*;
import java.util.Arrays;
import com.aizuda.boot.modules.common.constant.enums.SystemFieldsEnum;
import com.aizuda.boot.modules.common.constant.enums.NegotiationStatusEnum;
import com.aizuda.boot.modules.common.constant.enums.NegotiationNodeStatusEnum;
import com.aizuda.boot.modules.business.contract.mapper.ContractFieldMapper;
import com.aizuda.boot.modules.business.contract.mapper.ContractFieldValueMapper;
import com.aizuda.boot.modules.business.contract.mapper.ContractMapper;
import com.aizuda.boot.modules.business.contract.util.AuthUtil;
import com.aizuda.boot.modules.business.contract_operation_log.domain.entity.ContractOperationLog;
import com.aizuda.boot.modules.common.constant.enums.WorkFlowTypeEnums;
import com.aizuda.boot.modules.common.constant.enums.ActionTypeEnums;
import com.aizuda.boot.modules.common.constant.enums.SourceTypeEnums;
import com.aizuda.boot.modules.business.contract_operation_log.mapper.ContractOperationLogMapper;
import com.aizuda.boot.modules.system.service.ISysUserService;
import com.aizuda.boot.modules.system.service.ISysDepartmentService;
import com.aizuda.boot.modules.business.employee.domain.request.EmployeeQueryById;
import com.aizuda.boot.modules.business.employee.domain.response.EmployeeQueryShowVO;
import com.aizuda.boot.modules.system.entity.vo.department.DepartmentInfoDTO;
import com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationInstanceEntity;
import com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationNodeInstanceEntity;
import com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationParticipantEntity;
import com.aizuda.boot.modules.business.negotiation.entity.dto.CreateNegotiationReqDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationListReqDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.ContractVersionHistoryRespDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationAnnouncementRespDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationAnnouncementListRespDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationAnnouncementListReqDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationAnnouncementUpdateReqDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationAnnouncementDeleteReqDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationAnnouncementCreateReqDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.NegotiationInstanceAnnouncementUpdateReqDTO;
import com.aizuda.boot.modules.business.negotiation.entity.dto.InviteNegotiationReqDTO;
import com.aizuda.boot.modules.flw.entity.dto.ProcessApprovalDTO;
import com.aizuda.boot.modules.flw.service.IFlwProcessTaskService;
import com.aizuda.bpm.engine.core.FlowCreator;
import com.aizuda.bpm.engine.FlowLongEngine;
import com.aizuda.bpm.engine.entity.FlwTask;
import com.aizuda.bpm.engine.entity.FlwTaskActor;
import com.aizuda.bpm.engine.core.enums.PerformType;
import com.aizuda.bpm.engine.core.enums.ActorType;
import com.aizuda.bpm.engine.model.NodeModel;
import com.aizuda.bpm.engine.model.NodeAssignee;
import com.aizuda.bpm.engine.model.ProcessModel;
import com.aizuda.bpm.engine.entity.FlwInstance;
import com.aizuda.boot.modules.flw.flow.FlowHelper;
import com.aizuda.boot.modules.system.entity.SysUser;
import com.aizuda.boot.modules.system.mapper.SysUserMapper;
import com.aizuda.boot.modules.business.negotiation.entity.vo.CreateNegotiationRespDTO;
import com.aizuda.boot.modules.business.negotiation.entity.vo.NegotiationListRespDTO;
import com.aizuda.boot.modules.file.domain.entity.ContractFileEntity;
import com.aizuda.boot.modules.file.service.IContractFileService;
import com.aizuda.boot.modules.third.wps.domain.entity.FileHistory;
import com.aizuda.boot.modules.third.wps.mapper.FileHistoryMapper;
import com.aizuda.boot.modules.file.service.IFileInfoService;
import com.aizuda.boot.modules.file.domain.vo.FileVO;
import com.aizuda.boot.modules.business.negotiation.mapper.ContractNegotiationInstanceMapper;
import com.aizuda.boot.modules.business.negotiation.mapper.ContractNegotiationNodeInstanceMapper;
import com.aizuda.boot.modules.business.negotiation.mapper.ContractNegotiationParticipantMapper;
import com.aizuda.boot.modules.business.negotiation.mapper.ContractNegotiationManagementMapper;
import com.aizuda.boot.modules.business.negotiation.service.ContractNegotiationService;
import com.aizuda.boot.modules.business.contract.entity.ContractTypeEntity;
import com.aizuda.boot.modules.business.performance.mapper.ContractTypeMapper;
import com.aizuda.common.toolkit.JacksonUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.aizuda.bpm.engine.entity.FlwExtInstance;
import com.aizuda.bpm.mybatisplus.mapper.FlwExtInstanceMapper;
import com.aizuda.bpm.mybatisplus.mapper.FlwTaskActorMapper;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.Comparator;
import java.util.Objects;
import java.util.HashMap;
import java.util.Set;
import com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationManagementEntity;

import java.util.Date;

/**
 * 合同协商服务实现类
 */
@Slf4j
@Service
public class ContractNegotiationServiceImpl implements ContractNegotiationService {
    
    @Resource
    private ContractNegotiationInstanceMapper contractNegotiationInstanceMapper;
    
    @Resource
    private ContractNegotiationNodeInstanceMapper contractNegotiationNodeInstanceMapper;
    
    @Resource
    private ContractNegotiationParticipantMapper contractNegotiationParticipantMapper;
    
    @Resource
    private ContractNegotiationManagementMapper contractNegotiationManagementMapper;

    @Resource
    private ContractMapper contractMapper;
    
    @Resource
    private ContractTypeMapper contractTypeMapper;
    
    @Resource
    private ContractFieldValueMapper contractFieldValueMapper;
    
    @Resource
    private ContractFieldMapper contractFieldMapper;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private ISysDepartmentService sysDepartmentService;
    
    @Resource
    private IContractFileService contractFileService;
    
    @Resource
    private FileHistoryMapper fileHistoryMapper;
    
    @Resource
    private IFileInfoService fileInfoService;
    
    @Resource
    private ContractOperationLogMapper contractOperationLogMapper;

    @Resource
    private FlowLongEngine flowLongEngine;

    @Resource
    private FlwTaskActorMapper flwTaskActorMapper;

    @Resource
    private FlwExtInstanceMapper flwExtInstanceMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private IFlwProcessTaskService flwProcessTaskService;

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    
    @Override
    public Page<NegotiationListRespDTO> getNegotiationList(NegotiationListReqDTO dto) {
        UserInfo currentUser = AuthUtil.getCurrentUser();
        Long employeeId = null;

        if (currentUser != null && currentUser.getEmployeeId() != null) {
            employeeId = currentUser.getEmployeeId();
            log.debug("协商列表查询 - 当前用户ID: {}", employeeId);
        } else {
            log.warn("协商列表查询 - 无法获取当前用户信息，currentUser: {}", currentUser);
            // 如果无法获取用户信息，应该返回错误而不是使用默认值
            Page<NegotiationListRespDTO> emptyResult = new Page<>();
            emptyResult.setRecords(new ArrayList<>());
            emptyResult.setTotal(0);
            return emptyResult;
        }
        // 1. 构建分页对象
        Page<ContractNegotiationInstanceEntity> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        
        // 所有筛选逻辑都在SQL中处理，提升查询效率
        
        // 4. 统一查询，支持筛选条件和关键词搜索的任意组合
        String filterType = StringUtils.hasText(dto.getFilterType()) ? dto.getFilterType() : "ALL";
        String sortField = StringUtils.hasText(dto.getSortField()) ? dto.getSortField() : "startTime";
        String sortOrder = StringUtils.hasText(dto.getSortOrder()) ? dto.getSortOrder() : "DESC";
        
        log.debug("协商列表查询 - 用户ID: {}, 筛选类型: {}, 页码: {}/{}", 
                employeeId, filterType, dto.getPageNum(), dto.getPageSize());
        
        // 获取当前用户的租户权限列表 - 修改逻辑：优先使用当前租户，如果为空则使用租户列表
        String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;
        List<String> userTenantKeys;

        if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
            // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
            userTenantKeys = List.of(currentSysTenantKey);
        } else {
            // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
            userTenantKeys = AuthUtil.getUserTenantKeys();
        }
        Page<ContractNegotiationInstanceEntity> instancePage = null;
        try {
            instancePage = contractNegotiationInstanceMapper.selectNegotiationListByFilter(
                    page,
                    filterType,
                    employeeId,
                    userTenantKeys,
                    dto.getKeyword(),
                    sortField,
                    sortOrder,
                    dto.getFilters()
            );
            log.debug("协商列表查询成功: 总记录数={}, 当前页记录数={}", 
                    instancePage.getTotal(), instancePage.getRecords().size());
        } catch (Exception e) {
            log.error("协商列表查询失败", e);
            // 返回空结果而不是抛异常
            instancePage = new Page<>();
            instancePage.setRecords(new ArrayList<>());
            instancePage.setTotal(0);
            instancePage.setCurrent(dto.getPageNum());
            instancePage.setSize(dto.getPageSize());
        }
        
        // 5. 优化版本：批量查询所有关联数据，避免N+1查询问题
        Page<NegotiationListRespDTO> result = new Page<>();
        result.setCurrent(instancePage.getCurrent());
        result.setSize(instancePage.getSize());
        result.setTotal(instancePage.getTotal());
        result.setPages(instancePage.getPages());
        
        List<NegotiationListRespDTO> records = convertToRespDTOBatch(instancePage.getRecords());
        result.setRecords(records);
        
        return result;
    }

    //todo 目前只是手动添加配置，后续需要根据合同类型自动添加配置
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CreateNegotiationRespDTO createNegotiation(CreateNegotiationReqDTO dto) {
  /*      UserInfo currentUser = AuthUtil.getCurrentUser();
        if (currentUser == null || currentUser.getEmployeeId() == null) {
            throw new BizException("当前用户信息获取失败，无法创建协商");
        }
        
        Long applicantId = currentUser.getEmployeeId();
        log.info("创建协商 - 当前用户ID: {}, 合同ID: {}", applicantId, dto.getContractId());
        
        // 1. 验证合同是否存在
        ContractEntity contract = contractMapper.selectById(dto.getContractId());
        if (contract == null) {
            throw new BizException("合同不存在，合同ID: " + dto.getContractId());
        }
        
        // 2. 检查是否已存在该合同的协商实例
        List<ContractNegotiationInstanceEntity> existingInstances = contractNegotiationInstanceMapper.selectList(
                new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                        .eq(ContractNegotiationInstanceEntity::getContractId, dto.getContractId())
                        .in(ContractNegotiationInstanceEntity::getNegotiationStatus, 
                            Arrays.asList("IN_NEGOTIATION", "PENDING_NEGOTIATION"))
        );
        
        if (!existingInstances.isEmpty()) {
            throw new BizException("该合同已存在进行中的协商实例，无法重复创建");
        }*/
        //todo 协商流程上线后删除
        Long applicantId = 1L;
        // 3. 创建协商实例
        ContractNegotiationInstanceEntity instance = createNegotiationInstance(dto, applicantId);
        
        // 4. 创建协商节点实例
        List<ContractNegotiationNodeInstanceEntity> nodeInstances = createNegotiationNodes(instance.getId(), dto);
        
        // 5. 创建协商参与者
        List<ContractNegotiationParticipantEntity> participants = createNegotiationParticipants(
                instance.getId(), nodeInstances, dto);
        
        // 6. 构建响应
        CreateNegotiationRespDTO response = buildCreateResponse(instance, nodeInstances, participants);
        
        log.info("协商创建成功 - 协商实例ID: {}, 节点数量: {}, 参与者数量: {}", 
                instance.getId(), nodeInstances.size(), participants.size());
        
        return response;
    }

    /**
     * 创建协商实例
     */
    private ContractNegotiationInstanceEntity createNegotiationInstance(CreateNegotiationReqDTO dto, Long applicantId) {
        ContractNegotiationInstanceEntity instance = new ContractNegotiationInstanceEntity()
                .setContractId(dto.getContractId())
//                .setConfigId(dto.getConfigId())
                .setConfigId(1)
//                .setNegotiationStage(StringUtils.hasText(dto.getNegotiationStage()) ?
//                    dto.getNegotiationStage() : "发起合同申请")
                .setNegotiationStage("发起合同申请")
                .setNegotiationStatus("PENDING_NEGOTIATION")
                .setStartTime(LocalDateTime.now())
                .setApplicantId(applicantId)
                .setCreatedAt(LocalDateTime.now())
                .setUpdatedAt(LocalDateTime.now());
        
        contractNegotiationInstanceMapper.insert(instance);
        return instance;
    }
    
    /**
     * 创建协商节点实例
     */
    private List<ContractNegotiationNodeInstanceEntity> createNegotiationNodes(
            Integer instanceId, CreateNegotiationReqDTO dto) {
        
        List<ContractNegotiationNodeInstanceEntity> nodeInstances = new ArrayList<>();
        List<Integer> list = new ArrayList<Integer>();
        list.add(137);
        list.add(146);
        if (!CollectionUtils.isEmpty(list)){
            int sortOrder = 1;
            for (Integer roleId :list) {
                String nodeName = getNodeNameByRoleId(roleId);
                ContractNegotiationNodeInstanceEntity nodeInstance = new ContractNegotiationNodeInstanceEntity()
                        .setInstanceId(instanceId)
                        .setRoleId(roleId)
                        .setNodeName(nodeName)
                        .setStatus("NOT_START")
                        .setIsCurrentNode(sortOrder == 1) // 第一个节点设为当前节点
                        .setStartTime(LocalDateTime.now())
                        .setSortOrder(sortOrder)
                        .setCreatedAt(LocalDateTime.now())
                        .setUpdatedAt(LocalDateTime.now());
                
                contractNegotiationNodeInstanceMapper.insert(nodeInstance);
                nodeInstances.add(nodeInstance);
                sortOrder++;
            }
        }
        
        return nodeInstances;
    }
    
    /**
     * 创建协商参与者
     */
    private List<ContractNegotiationParticipantEntity> createNegotiationParticipants(
            Integer instanceId, 
            List<ContractNegotiationNodeInstanceEntity> nodeInstances, 
            CreateNegotiationReqDTO dto) {
        
        List<ContractNegotiationParticipantEntity> participants = new ArrayList<>();
        Set<Long> addedUserIds = new HashSet<>();
        
        // 1. 为每个节点创建对应角色的参与者
        for (ContractNegotiationNodeInstanceEntity nodeInstance : nodeInstances) {
            List<Long> roleUserIds = getRoleUserIds(nodeInstance.getRoleId());
            
            for (Long userId : roleUserIds) {
                if (!addedUserIds.contains(userId)) {
                    ContractNegotiationParticipantEntity participant = new ContractNegotiationParticipantEntity()
                            .setInstanceId(instanceId)
                            .setNodeInstanceId(nodeInstance.getId())
                            .setEmployeeId(userId)
                            .setParticipantType("NODE_PARTICIPANT")
                            .setIsViewed(false)
                            .setIsConfirmed(false)
                            .setCreatedAt(LocalDateTime.now())
                            .setUpdatedAt(LocalDateTime.now());
                    
                    contractNegotiationParticipantMapper.insert(participant);
                    participants.add(participant);
                    addedUserIds.add(userId);
                }
            }
        }
        
        return participants;
    }
    
    /**
     * 根据角色ID获取用户ID列表
     */
    private List<Long> getRoleUserIds(Integer roleId) {
        try {
            // TODO: 通过权限服务获取角色下的用户列表
            // 这里需要调用权限服务的接口来获取角色下的用户
            log.debug("获取角色用户列表 - 角色ID: {}", roleId);
            
            // 临时返回空列表，实际应该调用权限服务
            return new ArrayList<>();
        } catch (Exception e) {
            log.error("获取角色用户列表失败，角色ID: {}", roleId, e);
            return new ArrayList<>();
        }
    }
    
    /**
     * 构建创建协商响应
     */
    private CreateNegotiationRespDTO buildCreateResponse(
            ContractNegotiationInstanceEntity instance,
            List<ContractNegotiationNodeInstanceEntity> nodeInstances,
            List<ContractNegotiationParticipantEntity> participants) {
        
        CreateNegotiationRespDTO response = new CreateNegotiationRespDTO();
        response.setNegotiationId(instance.getId());
        response.setContractId(instance.getContractId());
        response.setNegotiationStage(instance.getNegotiationStage());
        response.setNegotiationStatus(NegotiationStatusEnum.getMsgByCode(instance.getNegotiationStatus()));
        response.setStartTime(instance.getStartTime().format(DATE_TIME_FORMATTER));
        response.setApplicantId(instance.getApplicantId());
        response.setChatGroupId(instance.getChatGroupId());
        response.setNodeCount(nodeInstances.size());
        response.setParticipantCount(participants.size());
        
        return response;
    }
    //todo 新增协商到这里结束


    /**
     * 批量转换为响应DTO（优化版本，避免N+1查询问题）
     */
    private List<NegotiationListRespDTO> convertToRespDTOBatch(List<ContractNegotiationInstanceEntity> instances) {
        if (instances.isEmpty()) {
            return new ArrayList<>();
        }
        

        
        // 1. 收集所有需要的ID
        List<Integer> contractIds = instances.stream()
                .map(ContractNegotiationInstanceEntity::getContractId)
                .distinct()
                .collect(Collectors.toList());
        
        List<Integer> instanceIds = instances.stream()
                .map(ContractNegotiationInstanceEntity::getId)
                .collect(Collectors.toList());
        
        List<Long> applicantIds = instances.stream()
                .map(ContractNegotiationInstanceEntity::getApplicantId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        
        // 2. 收集所有需要查询的用户ID（申请人 + 参与者）
        Set<Long> allUserIds = new HashSet<>(applicantIds);
        
        // 先查询参与者来收集所有用户ID
        if (!instanceIds.isEmpty()) {
            List<ContractNegotiationParticipantEntity> allParticipants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .in(ContractNegotiationParticipantEntity::getInstanceId, instanceIds)
            );
            
            // 收集参与者的用户ID
            for (ContractNegotiationParticipantEntity participant : allParticipants) {
                if (participant.getEmployeeId() != null) {
                    allUserIds.add(participant.getEmployeeId());
                }
            }
        }
        
        // 3. 批量查询合同信息
        final Map<Integer, ContractEntity> contractMap;
        if (!contractIds.isEmpty()) {
            List<ContractEntity> contracts = contractMapper.selectBatchIds(contractIds);
            contractMap = contracts.stream()
                    .collect(Collectors.toMap(ContractEntity::getId, c -> c));
        } else {
            contractMap = new HashMap<>();
        }
        
        // 3. 批量查询合同字段值（合同名称、编号、类型）
        final Map<Integer, Map<String, String>> contractFieldsMap;
        if (!contractIds.isEmpty()) {
            // 查询所有相关合同的字段值，然后通过fieldId关联字段定义
            List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectList(
                    new LambdaQueryWrapper<ContractFieldValueEntity>()
                            .in(ContractFieldValueEntity::getContractId, contractIds)
            );
            
            // 获取所有字段ID，用于批量查询字段定义
            Set<Long> fieldIds = fieldValues.stream()
                    .map(ContractFieldValueEntity::getFieldId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
            
            // 批量查询字段定义，建立fieldId -> fieldCode的映射
            Map<Long, String> fieldCodeMap = new HashMap<>();
            if (!fieldIds.isEmpty()) {
                List<ContractFieldEntity> contractFields = contractFieldMapper.selectBatchIds(fieldIds);
                fieldCodeMap = contractFields.stream()
                        .collect(Collectors.toMap(
                                ContractFieldEntity::getId,
                                ContractFieldEntity::getCode,
                                (existing, replacement) -> existing
                        ));
            }
            
            // 过滤出我们需要的字段（合同名称、编号、类型）
            final Map<Long, String> finalFieldCodeMap = fieldCodeMap;
            List<ContractFieldValueEntity> filteredFieldValues = fieldValues.stream()
                    .filter(fv -> {
                        String fieldCode = finalFieldCodeMap.get(fv.getFieldId());
                        return fieldCode != null && Arrays.asList("contract_name", "contract_number", "contract_type").contains(fieldCode);
                    })
                    .collect(Collectors.toList());
            
            // 按合同ID分组，再按字段编码分组
            contractFieldsMap = filteredFieldValues.stream()
                    .collect(Collectors.groupingBy(
                            ContractFieldValueEntity::getContractId,
                            Collectors.toMap(
                                    fv -> finalFieldCodeMap.get(fv.getFieldId()),
                                    ContractFieldValueEntity::getFieldValue,
                                    (existing, replacement) -> existing
                            )
                    ));
                    
            // 4. 批量查询合同类型名称，将合同类型ID转换为名称
            Set<String> contractTypeIds = filteredFieldValues.stream()
                    .filter(fv -> "contract_type".equals(finalFieldCodeMap.get(fv.getFieldId())))
                    .map(ContractFieldValueEntity::getFieldValue)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
                    
            if (!contractTypeIds.isEmpty()) {
                try {
                    // 将String类型的ID转换为Integer进行查询
                    List<Integer> typeIdList = contractTypeIds.stream()
                            .map(idStr -> {
                                try {
                                    return Integer.parseInt(idStr);
                                } catch (NumberFormatException e) {
                                    log.warn("合同类型ID格式错误: {}", idStr);
                                    return null;
                                }
                            })
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList());
                    
                    if (!typeIdList.isEmpty()) {
                        List<ContractTypeEntity> contractTypes = contractTypeMapper.selectBatchIds(typeIdList);
                        Map<String, String> typeIdToNameMap = contractTypes.stream()
                                .collect(Collectors.toMap(
                                        ct -> String.valueOf(ct.getId()),
                                        ct -> ct.getTypeName() != null ? ct.getTypeName() : String.valueOf(ct.getId()),
                                        (existing, replacement) -> existing
                                ));
                        
                        // 更新contractFieldsMap中的合同类型字段，将ID替换为名称
                        contractFieldsMap.forEach((contractId, fieldMap) -> {
                            String typeId = fieldMap.get("contract_type");
                            if (typeId != null && typeIdToNameMap.containsKey(typeId)) {
                                fieldMap.put("contract_type", typeIdToNameMap.get(typeId));
                            }
                        });
                    }
                } catch (Exception e) {
                    log.error("批量查询合同类型失败", e);
                }
            }
        } else {
            contractFieldsMap = new HashMap<>();
        }
        
        // 5. 批量查询所有用户信息（申请人 + 参与者）
        final Map<Long, UserInfoDTO> userInfoMap = new HashMap<>();
        final Map<Long, String> userDepartmentMap = new HashMap<>();
        if (!allUserIds.isEmpty()) {
            try {
                // 批量查询用户信息
                EmployeeQueryById queryRequest = new EmployeeQueryById();
                queryRequest.setEmployeeIds(new ArrayList<>(allUserIds));
                List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);
                
                // 构建用户信息Map和部门信息Map
                for (EmployeeQueryShowVO employee : employees) {
                    // 构建用户信息DTO
                    UserInfoDTO userInfo = new UserInfoDTO();
                    userInfo.setId(employee.getId());
                    userInfo.setName(employee.getName());
                    userInfo.setNickname(employee.getAliasName());
                    userInfo.setAvatar(employee.getAvatar());
                    userInfoMap.put(employee.getId(), userInfo);
                    
                    // 获取部门信息
                    if (employee.getDeptName() != null) {
                        userDepartmentMap.put(employee.getId(), employee.getDeptName());
                    }
                }
                

            } catch (Exception e) {
                log.error("批量查询用户信息失败", e);
                // 如果批量查询失败，fallback到单个查询
                for (Long userId : allUserIds) {
                    try {
                        UserInfoDTO userInfo = getUserInfo(userId);
                        if (userInfo != null) {
                            userInfoMap.put(userId, userInfo);
                        }
                        
                        DepartmentInfoDTO deptInfo = sysDepartmentService.getEmployeeMainDepartmentForCompatibility(userId);
                        if (deptInfo != null) {
                            userDepartmentMap.put(userId, deptInfo.getName());
                        }
                    } catch (Exception ex) {
                        log.warn("获取用户信息失败，用户ID: {}", userId, ex);
                    }
                }
            }
        }
        
        // 6. 批量查询节点信息
        final Map<Integer, List<ContractNegotiationNodeInstanceEntity>> nodesMap;
        if (!instanceIds.isEmpty()) {
            List<ContractNegotiationNodeInstanceEntity> allNodes = contractNegotiationNodeInstanceMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationNodeInstanceEntity>()
                            .in(ContractNegotiationNodeInstanceEntity::getInstanceId, instanceIds)
                            .orderByAsc(ContractNegotiationNodeInstanceEntity::getSortOrder)
            );
            
            nodesMap = allNodes.stream()
                    .collect(Collectors.groupingBy(ContractNegotiationNodeInstanceEntity::getInstanceId));
        } else {
            nodesMap = new HashMap<>();
        }
        
        // 7. 重新构建参与者Map（使用之前已查询的参与者数据）
        final Map<Integer, List<ContractNegotiationParticipantEntity>> participantsMap;
        if (!instanceIds.isEmpty()) {
            // 重新查询参与者（已经在用户ID收集时查询过了，但为了保持代码清晰，重新查询）
            List<ContractNegotiationParticipantEntity> allParticipants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .in(ContractNegotiationParticipantEntity::getInstanceId, instanceIds)
            );
            
            participantsMap = allParticipants.stream()
                    .collect(Collectors.groupingBy(ContractNegotiationParticipantEntity::getInstanceId));
        } else {
            participantsMap = new HashMap<>();
        }
        

        
        // 8. 批量转换DTO
        return instances.stream()
                .map(instance -> convertSingleRespDTO(
                        instance,
                        contractMap.get(instance.getContractId()),
                        contractFieldsMap.getOrDefault(instance.getContractId(), new HashMap<>()),
                        userInfoMap.get(instance.getApplicantId()),
                        userDepartmentMap.get(instance.getApplicantId()),
                        nodesMap.getOrDefault(instance.getId(), new ArrayList<>()),
                        participantsMap.getOrDefault(instance.getId(), new ArrayList<>()),
                        userInfoMap
                ))
                .collect(Collectors.toList());
    }
    
    /**
     * 单个DTO转换（使用预查询的数据）
     */
    private NegotiationListRespDTO convertSingleRespDTO(
            ContractNegotiationInstanceEntity instance,
            ContractEntity contract,
            Map<String, String> contractFields,
            UserInfoDTO applicantInfo,
            String departmentName,
            List<ContractNegotiationNodeInstanceEntity> nodes,
            List<ContractNegotiationParticipantEntity> participants,
            Map<Long, UserInfoDTO> userInfoMap) {
        
        NegotiationListRespDTO dto = new NegotiationListRespDTO();
        
        // 基础字段映射
        dto.setContractId(instance.getContractId());
        dto.setNegotiationInstanceId(instance.getId());
        dto.setNegotiationStage(instance.getNegotiationStage());
        dto.setNegotiationStatus(NegotiationStatusEnum.getMsgByCode(instance.getNegotiationStatus()));
        dto.setNegotiationStatusCode(instance.getNegotiationStatus());
        
        // 时间格式化
        if (instance.getStartTime() != null) {
            dto.setStartTime(instance.getStartTime().format(DATE_TIME_FORMATTER));
        }
        if (instance.getLastConfirmTime() != null) {
            dto.setLastConfirmTime(instance.getLastConfirmTime().format(DATE_TIME_FORMATTER));
        }
        
        // 设置合同信息（使用预查询的数据）
        dto.setContractName(contractFields.get("contract_name"));
        dto.setContractCode(contractFields.get("contract_number"));
        dto.setContractType(contractFields.get("contract_type"));
        
        // 设置申请人信息（使用预查询的数据）
        dto.setApplicant(applicantInfo);
        dto.setDepartment(departmentName);
        
        // 设置协商参与者（使用预查询的用户信息）
        dto.setNegotiators(getNegotiatorsFromParticipants(participants, userInfoMap));
        
        // 计算节点确认情况
        calculateNodeStatus(dto, nodes);
        
        // 计算协商进度
        calculateNegotiationProgressFromParticipants(dto, participants);
        
        // 设置确认进度
        setConfirmProgress(dto, nodes);
        
        // 设置已确认角色
        dto.setConfirmedRoles(getConfirmedRoles(nodes));
        
        return dto;
    }

    /**
     * 将实例实体转换为响应DTO（原版本，保留作为备用）
     */
    private NegotiationListRespDTO convertToRespDTO(ContractNegotiationInstanceEntity instance) {
        NegotiationListRespDTO dto = new NegotiationListRespDTO();
        
        // 基础字段映射
        dto.setContractId(instance.getContractId()); // 设置为合同ID
        dto.setNegotiationInstanceId(instance.getId()); // 设置协商实例ID
        dto.setNegotiationStage(instance.getNegotiationStage());
        // 将数据库中的协商状态code转换为对应的message
        dto.setNegotiationStatus(NegotiationStatusEnum.getMsgByCode(instance.getNegotiationStatus()));
        // 设置协商状态code
        dto.setNegotiationStatusCode(instance.getNegotiationStatus());
        
        // 时间格式化
        if (instance.getStartTime() != null) {
            dto.setStartTime(instance.getStartTime().format(DATE_TIME_FORMATTER));
        }
        if (instance.getLastConfirmTime() != null) {
            dto.setLastConfirmTime(instance.getLastConfirmTime().format(DATE_TIME_FORMATTER));
        }
        
        // 查询合同信息
        ContractEntity contract = contractMapper.selectById(instance.getContractId());
        if (contract != null) {
            // 设置合同名称和编号
            dto.setContractName(getContractName(instance.getContractId()));
            dto.setContractCode(getContractNumber(instance.getContractId()));
            
            // 设置合同类型
            dto.setContractType(getContractTypeString(instance.getContractId()));
        }
        
        // 设置申请人信息
        if (instance.getApplicantId() != null) {
            dto.setApplicant(getUserInfo(instance.getApplicantId()));
            dto.setDepartment(getDepartmentName(instance.getApplicantId()));
        }
        
        // 查询相关节点信息
        List<ContractNegotiationNodeInstanceEntity> nodes = contractNegotiationNodeInstanceMapper.selectList(
                new LambdaQueryWrapper<ContractNegotiationNodeInstanceEntity>()
                        .eq(ContractNegotiationNodeInstanceEntity::getInstanceId, instance.getId())
                        .orderByAsc(ContractNegotiationNodeInstanceEntity::getSortOrder)
        );
        
        // 查询协商参与者
        List<ContractNegotiationParticipantEntity> participants = contractNegotiationParticipantMapper.selectByInstanceId(instance.getId());
        
        // 设置协商参与者
        dto.setNegotiators(getNegotiatorsFromParticipantsOriginal(participants));
        
        // 计算节点确认情况
        calculateNodeStatus(dto, nodes);
        
        // 计算协商进度
        calculateNegotiationProgressFromParticipants(dto, participants);
        
        // 设置确认进度
        setConfirmProgress(dto, nodes);
        
        // 设置已确认角色
        dto.setConfirmedRoles(getConfirmedRoles(nodes));
        
        return dto;
    }
    
    /**
     * 获取合同名称
     */
    private String getContractName(Integer contractId) {
        return getFieldValueByFieldCode(contractId, SystemFieldsEnum.CONTRACT_NAME.getCode());
    }
    
    /**
     * 获取合同编号
     */
    private String getContractNumber(Integer contractId) {
        return getFieldValueByFieldCode(contractId, SystemFieldsEnum.CONTRACT_NUMBER.getCode());
    }
    
    /**
     * 根据字段Code获取字段值
     */
    private String getFieldValueByFieldCode(Integer contractId, String fieldCode) {
        List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getContractId, contractId)
                        .eq(ContractFieldValueEntity::getFieldCode, fieldCode)
        );
        
        if (!fieldValues.isEmpty()) {
            return fieldValues.get(0).getFieldValue();
        }
        return null;
    }
    
    /**
     * 获取合同类型字符串（包含层级）
     */
    private String getContractTypeString(Integer contractId) {
        String contractTypeIdStr = getFieldValueByFieldCode(contractId, SystemFieldsEnum.CONTRACT_TYPE.getCode());
        if (contractTypeIdStr == null) {
            return null;
        }
        
        try {
            Integer contractTypeId = Integer.parseInt(contractTypeIdStr);
            return buildContractTypeHierarchyString(contractTypeId);
        } catch (NumberFormatException e) {
            log.error("合同类型ID格式错误: {}", contractTypeIdStr, e);
            return null;
        }
    }
    
    /**
     * 构建合同类型层级字符串
     */
    private String buildContractTypeHierarchyString(Integer contractTypeId) {
        List<String> typeNames = new ArrayList<>();
        ContractTypeEntity currentType = contractTypeMapper.selectById(contractTypeId);
        
        // 递归查找所有父级类型
        while (currentType != null) {
            typeNames.add(0, currentType.getTypeName()); // 在列表开头插入
            
            if (currentType.getParentId() != null) {
                currentType = contractTypeMapper.selectById(currentType.getParentId());
            } else {
                break;
            }
        }
        
        return String.join("/", typeNames);
    }
    
    /**
     * 获取用户信息
     */
    private UserInfoDTO getUserInfo(Long userId) {
        try {
            // 使用本地服务获取用户信息
            EmployeeQueryById queryRequest = new EmployeeQueryById();
            queryRequest.setEmployeeIds(Collections.singletonList(userId));
            List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);
            
            if (!employees.isEmpty()) {
                EmployeeQueryShowVO employee = employees.get(0);
                UserInfoDTO dto = new UserInfoDTO();
                dto.setId(userId);
                dto.setName(employee.getName());
                dto.setAvatar(employee.getAvatar());
                dto.setNickname(employee.getName()); // 使用name作为nickname
                return dto;
            }
        } catch (Exception e) {
            log.error("获取用户信息失败，用户ID: {}", userId, e);
        }
        
        // 如果获取失败，返回基本信息
        UserInfoDTO dto = new UserInfoDTO();
        dto.setId(userId);
        return dto;
    }
    
    /**
     * 从参与者表获取协商参与者列表（使用预查询的用户信息）
     */
    private List<UserInfoDTO> getNegotiatorsFromParticipants(List<ContractNegotiationParticipantEntity> participants, Map<Long, UserInfoDTO> userInfoMap) {
        Set<Long> negotiatorIdSet = new HashSet<>();
        
        // 从参与者表中获取所有参与者ID
        for (ContractNegotiationParticipantEntity participant : participants) {
            if (participant.getEmployeeId() != null) {
                negotiatorIdSet.add(participant.getEmployeeId());
            }
        }
        
        // 将用户ID转换为用户信息对象（使用预查询的数据）
        List<UserInfoDTO> negotiators = new ArrayList<>();
        for (Long userId : negotiatorIdSet) {
            UserInfoDTO userInfo = userInfoMap.get(userId);
            if (userInfo != null) {
                negotiators.add(userInfo);
            }
        }
        
        return negotiators;
    }
    
    /**
     * 从参与者表获取协商参与者列表（原版本，保留作为备用）
     */
    private List<UserInfoDTO> getNegotiatorsFromParticipantsOriginal(List<ContractNegotiationParticipantEntity> participants) {
        Set<Long> negotiatorIdSet = new HashSet<>();
        
        // 从参与者表中获取所有参与者ID
        for (ContractNegotiationParticipantEntity participant : participants) {
            if (participant.getEmployeeId() != null) {
                negotiatorIdSet.add(participant.getEmployeeId());
            }
        }
        
        // 将用户ID转换为用户信息对象
        List<UserInfoDTO> negotiators = new ArrayList<>();
        for (Long userId : negotiatorIdSet) {
            UserInfoDTO userInfo = getUserInfo(userId);
            if (userInfo != null) {
                negotiators.add(userInfo);
            }
        }
        
        return negotiators;
    }
    
    /**
     * 计算节点确认状态
     */
    private void calculateNodeStatus(NegotiationListRespDTO dto, List<ContractNegotiationNodeInstanceEntity> nodes) {
        if (nodes.isEmpty()) {
            dto.setAllNodesConfirmed(false);
            return;
        }
        
        // 检查是否所有节点都已完成
        boolean allCompleted = nodes.stream()
                .allMatch(node -> "COMPLETED".equals(node.getStatus()));
        
        dto.setAllNodesConfirmed(allCompleted);
    }
    
    /**
     * 从参与者表计算协商进度
     */
    private void calculateNegotiationProgressFromParticipants(NegotiationListRespDTO dto, List<ContractNegotiationParticipantEntity> participants) {
        int totalUsers = participants.size();
        int confirmedUsers = 0;
        
        for (ContractNegotiationParticipantEntity participant : participants) {
            // 统计已确认的参与者
            if (participant.getIsConfirmed() != null && participant.getIsConfirmed()) {
                confirmedUsers++;
            }
        }
        
        dto.setNegotiationProgress(confirmedUsers + "/" + totalUsers);
    }
    
    /**
     * 设置确认进度
     */
    private void setConfirmProgress(NegotiationListRespDTO dto, List<ContractNegotiationNodeInstanceEntity> nodes) {
        if (nodes.isEmpty()) {
            dto.setConfirmProgress("全部节点未完成");
            return;
        }
        
        // 检查是否所有节点都完成
        boolean allCompleted = nodes.stream()
                .allMatch(node -> "COMPLETED".equals(node.getStatus()));
        
        if (allCompleted) {
            dto.setConfirmProgress("全部节点已完成");
        } else {
            dto.setConfirmProgress("全部节点未完成");
        }
    }
    
    /**
     * 获取已确认角色
     */
    private String getConfirmedRoles(List<ContractNegotiationNodeInstanceEntity> nodes) {
        Set<Integer> confirmedRoleIds = new HashSet<>();
        
        // 查找状态为COMPLETED的节点的roleId
        for (ContractNegotiationNodeInstanceEntity node : nodes) {
            if ("COMPLETED".equals(node.getStatus()) && node.getRoleId() != null) {
                confirmedRoleIds.add(node.getRoleId());
            }
        }
        
        // 获取角色名称并用逗号连接
        List<String> roleNames = new ArrayList<>();
        for (Integer roleId : confirmedRoleIds) {
            String roleName = getRoleNameById(roleId.longValue());
            if (StringUtils.hasText(roleName)) {
                roleNames.add(roleName);
            }
        }
        
        return String.join(",", roleNames);
    }
    
    /**
     * 根据角色ID获取角色名称
     */
    private String getRoleNameById(Long roleId) {
        try {
            // TODO: 角色信息查询功能暂未实现，返回默认值
            log.debug("角色信息查询功能暂未实现，角色ID: {}", roleId);
            return "角色" + roleId; // 临时返回值
        } catch (Exception e) {
            log.error("获取角色信息失败，角色ID: {}", roleId, e);
        }
        return null;
    }
    
    /**
     * 根据申请人ID获取主部门名称
     */
    private String getDepartmentName(Long applicantId) {
        try {
            // 使用本地服务获取主部门信息
            DepartmentInfoDTO deptInfo = sysDepartmentService.getEmployeeMainDepartmentForCompatibility(applicantId);
            if (deptInfo != null) {
                return deptInfo.getName();
            }
        } catch (Exception e) {
            log.error("获取申请人部门信息失败，申请人ID: {}", applicantId, e);
        }
        return null;
    }
    
    
    /**
     * 获取员工信息
     * @param employeeId 员工ID
     * @return 员工信息
     */
    private EmployeeQueryShowVO getEmployeeInfo(Long employeeId) {
        try {
            EmployeeQueryById queryRequest = new EmployeeQueryById();
            queryRequest.setEmployeeIds(Collections.singletonList(employeeId));
            List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);
            
            if (!employees.isEmpty()) {
                return employees.get(0);
            }
        } catch (Exception e) {
            log.error("获取员工信息失败，员工ID: {}", employeeId, e);
        }
        return null;
    }

    @Override
    public ContractNegotiationInstanceEntity getNegotiationByContractId(Integer contractId) {
        // 查询进行中的协商实例
        return contractNegotiationInstanceMapper.selectOne(
                new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                        .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                        .eq(ContractNegotiationInstanceEntity::getNegotiationStatus, 
                            NegotiationStatusEnum.IN_NEGOTIATION.getCode())
                        .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                        .last("LIMIT 1")
        );
    }
    
    @Override
    public ContractNegotiationInstanceEntity getNegotiationByContractIdAllStatus(Integer contractId) {
        // 查询所有状态的协商实例（包含进行中、已完成、已取消等）
        return contractNegotiationInstanceMapper.selectOne(
                new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                        .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                        .in(ContractNegotiationInstanceEntity::getNegotiationStatus, 
                            Arrays.asList(
                                NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                NegotiationStatusEnum.NEGOTIATION_COMPLETE.getCode(),
                                NegotiationStatusEnum.PENDING_NEGOTIATION.getCode(),
                                NegotiationStatusEnum.NEGOTIATION_CANCELED.getCode()
                            ))
                        .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                        .last("LIMIT 1")
        );
    }
    
    @Override
    public ContractNegotiationNodeInstanceEntity getCurrentTask(Integer negotiationInstanceId) {
        // 查询当前节点（isCurrentNode = true）
        return contractNegotiationNodeInstanceMapper.selectOne(
                new LambdaQueryWrapper<ContractNegotiationNodeInstanceEntity>()
                        .eq(ContractNegotiationNodeInstanceEntity::getInstanceId, negotiationInstanceId)
                        .eq(ContractNegotiationNodeInstanceEntity::getIsCurrentNode, true)
                        .orderByAsc(ContractNegotiationNodeInstanceEntity::getSortOrder)
                        .last("LIMIT 1")
        );
    }
    
    @Override
    public Map<String, Object> getNegotiationFullInfo(Integer contractId) {
        Map<String, Object> result = new HashMap<>();
        
        // 1. 查询协商实例（包含所有状态：协商中、协商完成、协商取消等）
        ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                        .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                        .in(ContractNegotiationInstanceEntity::getNegotiationStatus, 
                            Arrays.asList(
                                NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                NegotiationStatusEnum.NEGOTIATION_COMPLETE.getCode(),
                                NegotiationStatusEnum.PENDING_NEGOTIATION.getCode(),
                                NegotiationStatusEnum.NEGOTIATION_CANCELED.getCode()
                            ))
                        .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                        .last("LIMIT 1")
        );
        if (instance == null) {
            return result;
        }
        
        // 基本信息
        result.put("negotiationInstanceId", instance.getId());
        result.put("contractId", instance.getContractId());
        result.put("processInstanceId", instance.getProcessInstanceId());
        result.put("negotiationStatus", instance.getNegotiationStatus());
        result.put("negotiationStage", instance.getNegotiationStage());
        result.put("announcementText", instance.getAnnouncementText()); // 添加协商公告文本
        result.put("startTime", instance.getStartTime() != null ?
                instance.getStartTime().format(DATE_TIME_FORMATTER) : null);
        result.put("lastConfirmTime", instance.getLastConfirmTime() != null ? 
                instance.getLastConfirmTime().format(DATE_TIME_FORMATTER) : null);
        result.put("applicantId", instance.getApplicantId());
        
        // 添加申请人详细信息
        if (instance.getApplicantId() != null) {
            EmployeeQueryShowVO applicant = getEmployeeInfo(instance.getApplicantId());
            if (applicant != null) {
                result.put("applicantName", applicant.getName());
                result.put("applicantNickname", applicant.getAliasName());
                result.put("applicantAvatar", applicant.getAvatar());
            }
        }
        
        // 2. 查询所有节点实例
        List<ContractNegotiationNodeInstanceEntity> nodeInstances = contractNegotiationNodeInstanceMapper.selectList(
                new LambdaQueryWrapper<ContractNegotiationNodeInstanceEntity>()
                        .eq(ContractNegotiationNodeInstanceEntity::getInstanceId, instance.getId())
                        .orderByAsc(ContractNegotiationNodeInstanceEntity::getSortOrder)
        );
        
        List<Map<String, Object>> nodeList = new ArrayList<>();
        ContractNegotiationNodeInstanceEntity currentNode = null;
        
        for (ContractNegotiationNodeInstanceEntity node : nodeInstances) {
            Map<String, Object> nodeInfo = new HashMap<>();
            nodeInfo.put("nodeId", node.getId());
            nodeInfo.put("roleId", node.getRoleId());
            nodeInfo.put("nodeName", node.getNodeName());
            nodeInfo.put("status", node.getStatus());
            nodeInfo.put("isCurrentNode", node.getIsCurrentNode());
            nodeInfo.put("taskId", node.getTaskId());
            nodeInfo.put("sortOrder", node.getSortOrder());
            nodeInfo.put("startTime", node.getStartTime() != null ? 
                    node.getStartTime().format(DATE_TIME_FORMATTER) : null);
            nodeInfo.put("finishTime", node.getFinishTime() != null ? 
                    node.getFinishTime().format(DATE_TIME_FORMATTER) : null);
            
            // 添加转办用户详细信息
            if (node.getTransferUserId() != null) {
                nodeInfo.put("transferUserId", node.getTransferUserId());
                EmployeeQueryShowVO transferUser = getEmployeeInfo(node.getTransferUserId());
                if (transferUser != null) {
                    nodeInfo.put("transferUserName", transferUser.getName());
                    nodeInfo.put("transferUserNickname", transferUser.getAliasName());
                    nodeInfo.put("transferUserAvatar", transferUser.getAvatar());
                }
            }
            
            if (node.getOriginalUserId() != null) {
                nodeInfo.put("originalUserId", node.getOriginalUserId());
                EmployeeQueryShowVO originalUser = getEmployeeInfo(node.getOriginalUserId());
                if (originalUser != null) {
                    nodeInfo.put("originalUserName", originalUser.getName());
                    nodeInfo.put("originalUserNickname", originalUser.getAliasName());
                    nodeInfo.put("originalUserAvatar", originalUser.getAvatar());
                }
            }
            
            // 解析任务信息快照
            if (StringUtils.hasText(node.getRuleConfigSnapshot())) {
                try {
                    Map<String, Object> taskInfo = JacksonUtils.readMap(node.getRuleConfigSnapshot());
                    nodeInfo.put("taskInfo", taskInfo);
                } catch (Exception e) {
                    log.error("解析任务信息失败", e);
                }
            }
            
            // 查询该节点的参与者
            List<ContractNegotiationParticipantEntity> participants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getNodeInstanceId, node.getId())
            );
            
            List<Map<String, Object>> participantList = new ArrayList<>();
            for (ContractNegotiationParticipantEntity participant : participants) {
                Map<String, Object> participantInfo = new HashMap<>();
                participantInfo.put("participantId", participant.getId());
                participantInfo.put("employeeId", participant.getEmployeeId());
                participantInfo.put("participantType", participant.getParticipantType());
                participantInfo.put("isViewed", participant.getIsViewed());
                participantInfo.put("viewedTime", participant.getViewedTime() != null ? 
                        participant.getViewedTime().format(DATE_TIME_FORMATTER) : null);
                participantInfo.put("isConfirmed", participant.getIsConfirmed());
                participantInfo.put("confirmedTime", participant.getConfirmedTime() != null ? 
                        participant.getConfirmedTime().format(DATE_TIME_FORMATTER) : null);
                
                // 获取员工信息
                EmployeeQueryShowVO employee = getEmployeeInfo(participant.getEmployeeId());
                if (employee != null) {
                    participantInfo.put("employeeName", employee.getName());
                    participantInfo.put("employeeNickname", employee.getAliasName());
                    participantInfo.put("employeeAvatar", employee.getAvatar());
                }
                
                participantList.add(participantInfo);
            }
            
            nodeInfo.put("participants", participantList);
            nodeList.add(nodeInfo);
            
            // 记录当前节点
            if (Boolean.TRUE.equals(node.getIsCurrentNode())) {
                currentNode = node;
            }
        }
        
        result.put("nodes", nodeList);
        
        // 3. 当前节点信息
        if (currentNode != null) {
            result.put("currentNodeId", currentNode.getId());
            result.put("currentTaskId", currentNode.getTaskId());
            result.put("currentNodeStatus", currentNode.getStatus());
            result.put("currentRoleId", currentNode.getRoleId());
        }
        
        // 4. 查询所有参与者（包括旁观者）
        List<ContractNegotiationParticipantEntity> allParticipants = contractNegotiationParticipantMapper.selectList(
                new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                        .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
        );
        
        // 统计信息
        long totalParticipants = allParticipants.size();
        long confirmedCount = allParticipants.stream()
                .filter(p -> Boolean.TRUE.equals(p.getIsConfirmed()))
                .count();
        long viewedCount = allParticipants.stream()
                .filter(p -> Boolean.TRUE.equals(p.getIsViewed()))
                .count();
        
        Map<String, Object> statistics = new HashMap<>();
        statistics.put("totalParticipants", totalParticipants);
        statistics.put("confirmedCount", confirmedCount);
        statistics.put("viewedCount", viewedCount);
        statistics.put("confirmProgress", totalParticipants > 0 ? 
                String.format("%.2f%%", (confirmedCount * 100.0 / totalParticipants)) : "0%");
        
        result.put("statistics", statistics);
        
        // 5. 添加negotiators - 当前协商实例的所有参与者信息
        List<Map<String, Object>> negotiators = new ArrayList<>();
        for (ContractNegotiationParticipantEntity participant : allParticipants) {
            Map<String, Object> negotiatorInfo = new HashMap<>();
            negotiatorInfo.put("id", participant.getEmployeeId().toString());
            negotiatorInfo.put("participantType", participant.getParticipantType());
            negotiatorInfo.put("isViewed", participant.getIsViewed());
            negotiatorInfo.put("isConfirmed", participant.getIsConfirmed());
            negotiatorInfo.put("viewedTime", participant.getViewedTime() != null ? 
                    participant.getViewedTime().format(DATE_TIME_FORMATTER) : null);
            
            // 添加节点名称
            if (participant.getNodeInstanceId() != null) {
                log.debug("参与者 {} 的nodeInstanceId: {}", participant.getEmployeeId(), participant.getNodeInstanceId());
                ContractNegotiationNodeInstanceEntity nodeInstance = contractNegotiationNodeInstanceMapper.selectById(participant.getNodeInstanceId());
                if (nodeInstance != null && nodeInstance.getNodeName() != null) {
                    log.debug("找到节点实例，nodeName: {}", nodeInstance.getNodeName());
                    negotiatorInfo.put("nodename", nodeInstance.getNodeName());
                } else {
                    log.warn("未找到节点实例或节点名称为空，nodeInstanceId: {}", participant.getNodeInstanceId());
                    negotiatorInfo.put("nodename", "未知节点");
                }
            } else {
                log.debug("参与者 {} 的nodeInstanceId为空，可能是观察者", participant.getEmployeeId());
                negotiatorInfo.put("nodename", "观察者");
            }
            
            // 获取员工信息
            EmployeeQueryShowVO employee = getEmployeeInfo(participant.getEmployeeId());
            if (employee != null) {
                negotiatorInfo.put("name", employee.getName());
                negotiatorInfo.put("nickname", employee.getAliasName());
                negotiatorInfo.put("avatar", employee.getAvatar());
                
                // 获取主部门信息
                DepartmentInfoDTO mainDepartment = sysDepartmentService.getEmployeeMainDepartmentForCompatibility(participant.getEmployeeId());
                if (mainDepartment != null) {
                    negotiatorInfo.put("mainDepartment", mainDepartment.getName());
                } else {
                    negotiatorInfo.put("mainDepartment", null);
                }
            }
            
            negotiators.add(negotiatorInfo);
        }
        
        result.put("negotiators", negotiators);
        
        return result;
    }

    /**
     * 根据角色ID获取节点名称
     */
    private String getNodeNameByRoleId(Integer roleId) {
        try {
            // TODO: 根据实际业务需求，这里可以实现获取角色对应节点名称的逻辑
            // 可以从数据库查询或者根据roleId映射
            if (roleId == 137) {
                return "初审节点";
            } else if (roleId == 146) {
                return "终审节点";
            } else {
                return "审批节点-" + roleId;
            }
        } catch (Exception e) {
            log.error("获取节点名称失败，角色ID: {}", roleId, e);
            return "未知节点-" + roleId;
        }
    }

    @Override
    public void updateParticipantViewStatus(Integer contractId, Long userId) {
        try {
            // 1. 查询协商实例（包含所有状态）
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus, 
                                Arrays.asList(
                                    NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.NEGOTIATION_COMPLETE.getCode(),
                                    NegotiationStatusEnum.PENDING_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.NEGOTIATION_CANCELED.getCode()
                                ))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );
            
            if (instance == null) {
                log.warn("未找到合同的协商实例，合同ID: {}", contractId);
                return;
            }
            
            // 2. 检查用户是否是申请人
            boolean isApplicant = userId.equals(instance.getApplicantId());

            // 3. 查询当前用户的参与者记录
            List<ContractNegotiationParticipantEntity> participants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                            .eq(ContractNegotiationParticipantEntity::getEmployeeId, userId)
                            .orderByAsc(ContractNegotiationParticipantEntity::getId)
            );

            // 4. 如果用户在参与者表中，更新参与者的查看状态
            if (!participants.isEmpty()) {
                ContractNegotiationParticipantEntity participant = participants.get(0);

                if (participants.size() > 1) {
                    log.debug("用户在协商中有多个参与者记录，使用第一个记录，合同ID: {}, 用户ID: {}, 记录数: {}",
                            contractId, userId, participants.size());
                }

                if (!Boolean.TRUE.equals(participant.getIsViewed())) {
                    participant.setIsViewed(true);
                    participant.setViewedTime(LocalDateTime.now());
                    participant.setUpdatedAt(LocalDateTime.now());

                    contractNegotiationParticipantMapper.updateById(participant);
                    log.debug("更新参与者查看状态成功，合同ID: {}, 用户ID: {}, 参与者ID: {}",
                            contractId, userId, participant.getId());
                } else {
                    log.debug("参与者已经查看过，合同ID: {}, 用户ID: {}", contractId, userId);
                }
                return;
            }

            // 5. 如果用户是申请人但不在参与者表中，记录查看状态（通过操作日志实现）
            if (isApplicant) {
                log.info("申请人不在参与者表中，查看状态通过操作日志记录，合同ID: {}, 用户ID: {}", contractId, userId);
                // 申请人的查看状态通过操作日志来维护，这里不需要额外操作
                return;
            }

            // 6. 其他用户（既不在参与者表中，也不是申请人）
            log.info("用户既不是参与者也不是申请人，无需更新查看状态，合同ID: {}, 用户ID: {}", contractId, userId);
            
        } catch (Exception e) {
            log.error("更新参与者查看状态失败，合同ID: {}, 用户ID: {}", contractId, userId, e);
        }
    }
    
    @Override
    public boolean hasUserViewedNegotiation(Integer contractId, Long userId) {
        try {
            // 1. 查询协商实例（包含所有状态）
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus,
                                Arrays.asList(
                                    NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.NEGOTIATION_COMPLETE.getCode(),
                                    NegotiationStatusEnum.PENDING_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.NEGOTIATION_CANCELED.getCode()
                                ))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (instance == null) {
                log.warn("未找到合同的协商实例，合同ID: {}", contractId);
                return false;
            }

            // 2. 检查用户是否是申请人
            boolean isApplicant = userId.equals(instance.getApplicantId());
            log.info("用户身份检查 - 合同ID: {}, 用户ID: {}, 是否申请人: {}, 申请人ID: {}",
                    contractId, userId, isApplicant, instance.getApplicantId());

            // 3. 查询当前用户的参与者记录
            List<ContractNegotiationParticipantEntity> participants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                            .eq(ContractNegotiationParticipantEntity::getEmployeeId, userId)
                            .orderByAsc(ContractNegotiationParticipantEntity::getId)
            );

            // 4. 如果用户在参与者表中，使用参与者表的查看状态
            if (!participants.isEmpty()) {
                boolean hasViewed = participants.stream()
                        .anyMatch(p -> Boolean.TRUE.equals(p.getIsViewed()));
                log.info("参与者查看状态检查 - 合同ID: {}, 用户ID: {}, 已查看: {}",
                        contractId, userId, hasViewed);
                return hasViewed;
            }

            // 5. 如果用户是申请人但不在参与者表中，检查操作日志表
            if (isApplicant) {
                boolean hasViewLog = hasApplicantViewedContractLog(contractId, userId);
                log.info("申请人查看日志检查 - 合同ID: {}, 用户ID: {}, 已查看: {}",
                        contractId, userId, hasViewLog);
                return hasViewLog;
            }

            // 6. 其他用户（既不在参与者表中，也不是申请人）返回false，不启用去重机制
            log.info("用户既不是参与者也不是申请人，不启用去重机制 - 合同ID: {}, 用户ID: {}", contractId, userId);
            return false;

        } catch (Exception e) {
            log.error("检查用户查看状态失败，合同ID: {}, 用户ID: {}", contractId, userId, e);
            return false;
        }
    }

    /**
     * 检查申请人是否已经记录过查看合同的日志
     * @param contractId 合同ID
     * @param userId 申请人用户ID
     * @return true-已记录过，false-未记录过
     */
    private boolean hasApplicantViewedContractLog(Integer contractId, Long userId) {
        try {
            // 查询操作日志表，检查是否已存在该申请人的查看记录
            long count = contractOperationLogMapper.selectCount(
                new LambdaQueryWrapper<ContractOperationLog>()
                    .eq(ContractOperationLog::getContractId, contractId.longValue())
                    .eq(ContractOperationLog::getFlowType, WorkFlowTypeEnums.NEGOTIATION_WORKFLOW.getCode())
                    .eq(ContractOperationLog::getActionType, ActionTypeEnums.VIEW_CONTRACT.getCode())
                    .eq(ContractOperationLog::getUserId, userId)
            );

            boolean hasViewed = count > 0;
            log.debug("申请人查看日志检查 - 合同ID: {}, 用户ID: {}, 已记录: {}, 记录数: {}",
                    contractId, userId, hasViewed, count);

            return hasViewed;
        } catch (Exception e) {
            log.error("检查申请人查看日志失败，合同ID: {}, 用户ID: {}", contractId, userId, e);
            return false; // 出错时返回false，允许记录日志
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resumeNegotiationByContractId(Integer contractId, String announcementText) {
        try {
            log.info("开始激活协商，合同ID: {}", contractId);

            // 1. 查询协商实例
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus,
                                Arrays.asList(
                                    NegotiationStatusEnum.PENDING_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.NEGOTIATION_CANCELED.getCode(),
                                        NegotiationStatusEnum.IN_NEGOTIATION.getCode()
                                ))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (instance == null) {
                log.warn("未找到可激活的协商实例，合同ID: {}", contractId);
                return false;
            }

            log.info("找到协商实例，实例ID: {}, 当前状态: {}", instance.getId(), instance.getNegotiationStatus());

             // 2. 使用传入的协商公告文本
             String finalAnnouncementText = announcementText != null ? announcementText : "";
             log.info("使用传入的协商公告文本，长度: {}", finalAnnouncementText.length());

             // 3. 更新协商实例状态为协商中，并设置协商公告文本
             LocalDateTime now = LocalDateTime.now();
             int instanceUpdatedCount = contractNegotiationInstanceMapper.update(null,
                     new LambdaUpdateWrapper<ContractNegotiationInstanceEntity>()
                             .eq(ContractNegotiationInstanceEntity::getId, instance.getId())
                             .set(ContractNegotiationInstanceEntity::getNegotiationStatus, NegotiationStatusEnum.IN_NEGOTIATION.getCode())
                             .set(ContractNegotiationInstanceEntity::getAnnouncementText, finalAnnouncementText)
                             .set(ContractNegotiationInstanceEntity::getUpdatedAt, now)
             );

            if (instanceUpdatedCount == 0) {
                log.error("更新协商实例状态失败，实例ID: {}", instance.getId());
                return false;
            }

            log.info("协商实例状态更新成功，实例ID: {}, 新状态: {}", instance.getId(), NegotiationStatusEnum.IN_NEGOTIATION.getCode());

            // 3. 激活第一个节点
            List<ContractNegotiationNodeInstanceEntity> nodeInstances = contractNegotiationNodeInstanceMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationNodeInstanceEntity>()
                            .eq(ContractNegotiationNodeInstanceEntity::getInstanceId, instance.getId())
                            .orderByAsc(ContractNegotiationNodeInstanceEntity::getSortOrder)
            );

            if (nodeInstances.isEmpty()) {
                log.warn("未找到协商节点实例，实例ID: {}", instance.getId());
                return false;
            }

                         // 激活第一个节点
             ContractNegotiationNodeInstanceEntity firstNode = nodeInstances.get(0);
             int nodeUpdatedCount = contractNegotiationNodeInstanceMapper.update(null,
                     new LambdaUpdateWrapper<ContractNegotiationNodeInstanceEntity>()
                             .eq(ContractNegotiationNodeInstanceEntity::getId, firstNode.getId())
                             .set(ContractNegotiationNodeInstanceEntity::getStatus, NegotiationNodeStatusEnum.PROCESSING.getCode())
                             .set(ContractNegotiationNodeInstanceEntity::getIsCurrentNode, true)
                             .set(ContractNegotiationNodeInstanceEntity::getStartTime, now)
                             .set(ContractNegotiationNodeInstanceEntity::getUpdatedAt, now)
             );

            if (nodeUpdatedCount == 0) {
                log.error("激活第一个节点失败，节点ID: {}", firstNode.getId());
                return false;
            }

                         log.info("第一个节点激活成功，节点ID: {}, 节点名称: {}", firstNode.getId(), firstNode.getNodeName());



             log.info("协商激活完成，合同ID: {}, 协商实例ID: {}", contractId, instance.getId());
            return true;

        } catch (Exception e) {
            log.error("激活协商失败，合同ID: {}", contractId, e);
            return false;
        }
         }

    @Override
    public List<ContractVersionHistoryRespDTO> getContractVersionHistory(Integer contractId) {
        List<ContractVersionHistoryRespDTO> result = new ArrayList<>();
        
        try {
            // 1. 查询contract_file表中该合同的所有数据，按major_version分组
            List<ContractFileEntity> allFiles = contractFileService.list(
                    new LambdaQueryWrapper<ContractFileEntity>()
                            .eq(ContractFileEntity::getContractId, contractId)
                            .orderByDesc(ContractFileEntity::getMajorVersion)
                            .orderByDesc(ContractFileEntity::getMinorVersion)
            );
            
            if (allFiles.isEmpty()) {
                return result;
            }
            
            // 2. 按major_version分组
            Map<Integer, List<ContractFileEntity>> groupedByMajorVersion = allFiles.stream()
                    .collect(Collectors.groupingBy(ContractFileEntity::getMajorVersion));
            
            // 3. 获取最高的major_version，用于判断状态
            Integer maxMajorVersion = Collections.max(groupedByMajorVersion.keySet());
            
            // 4. 处理每个major_version
            for (Map.Entry<Integer, List<ContractFileEntity>> entry : groupedByMajorVersion.entrySet()) {
                Integer majorVersion = entry.getKey();
                List<ContractFileEntity> filesInVersion = entry.getValue();
                
                // 排序：minor_version升序
                filesInVersion.sort(Comparator.comparing(ContractFileEntity::getMinorVersion));
                
                ContractVersionHistoryRespDTO versionHistory = new ContractVersionHistoryRespDTO();
                
                // 设置版本号
                versionHistory.setVersion("V" + majorVersion + ".0");
                
                // 获取minor_version=0的记录作为主记录
                ContractFileEntity mainRecord = filesInVersion.stream()
                        .filter(f -> f.getMinorVersion() == 0)
                        .findFirst()
                        .orElse(filesInVersion.get(0));
                
                // 设置操作人信息（major_version, minor_version=0的创建人）
                versionHistory.setOperator(buildOperatorInfo(mainRecord.getCreateId()));
                
                // 设置文件信息
                versionHistory.setFileInfo(buildFileInfo(mainRecord.getFileId(), mainRecord.getFileHistoryVersion()));
                
                // 设置创建时间
                versionHistory.setCreateTime(formatDateTime(mainRecord.getCreateTime()));
                
                // 设置确认人员列表（当前major_version下minor_version!=0的所有人员）
                List<ContractVersionHistoryRespDTO.OperatorInfoDTO> confirmedUsers = filesInVersion.stream()
                        .filter(f -> f.getMinorVersion() != 0)
                        .map(f -> buildOperatorInfo(f.getCreateId()))
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());
                versionHistory.setConfirmedUsers(confirmedUsers);
                
                // 设置状态
                if (majorVersion.equals(maxMajorVersion)) {
                    versionHistory.setStatus("最终稿");
                } else {
                    versionHistory.setStatus("版本终稿");
                }
                
                // 设置process列表
                List<ContractVersionHistoryRespDTO.ProcessItemDTO> processList = new ArrayList<>();
                for (ContractFileEntity file : filesInVersion) {
                    ContractVersionHistoryRespDTO.ProcessItemDTO processItem = new ContractVersionHistoryRespDTO.ProcessItemDTO();
                    
                    // 设置状态
                    if (file.getMinorVersion() == 0) {
                        processItem.setStatus("初始稿");
                    } else {
                        processItem.setStatus("确认稿");
                    }
                    
                    // 设置操作人信息
                    processItem.setOperator(buildOperatorInfo(file.getCreateId()));
                    
                    // 设置创建时间
                    processItem.setCreateTime(formatDateTime(file.getCreateTime()));
                    
                    // 设置文件信息
                    processItem.setFileInfo(buildFileInfo(file.getFileId(), file.getFileHistoryVersion()));
                    
                    processList.add(processItem);
                }
                versionHistory.setProcess(processList);
                
                result.add(versionHistory);
            }
            
            // 5. 按major_version降序排序
            result.sort((a, b) -> {
                Integer versionA = Integer.parseInt(a.getVersion().substring(1, a.getVersion().indexOf('.')));
                Integer versionB = Integer.parseInt(b.getVersion().substring(1, b.getVersion().indexOf('.')));
                return versionB.compareTo(versionA);
            });
            
        } catch (Exception e) {
            log.error("获取合同版本历史失败，合同ID: {}", contractId, e);
        }
        
        return result;
    }
    
    /**
     * 构建操作人信息
     */
    private ContractVersionHistoryRespDTO.OperatorInfoDTO buildOperatorInfo(Long userId) {
        if (userId == null) {
            return null;
        }
        
        try {
            EmployeeQueryById queryRequest = new EmployeeQueryById();
            queryRequest.setEmployeeIds(Collections.singletonList(userId));
            List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);
            
            if (!employees.isEmpty()) {
                EmployeeQueryShowVO employee = employees.get(0);
                ContractVersionHistoryRespDTO.OperatorInfoDTO operator = new ContractVersionHistoryRespDTO.OperatorInfoDTO();
                operator.setId(userId);
                operator.setName(employee.getName());
                operator.setAvatar(employee.getAvatar());
                return operator;
            }
        } catch (Exception e) {
            log.error("获取用户信息失败，用户ID: {}", userId, e);
        }
        
        return null;
    }
    
    /**
     * 构建文件信息
     */
    private ContractVersionHistoryRespDTO.FileInfoDTO buildFileInfo(Long fileId, Integer fileHistoryVersion) {
        if (fileId == null) {
            return null;
        }
        
        try {
            SingleResponse<FileVO> response = fileInfoService.getFileInfoById(fileId.toString());
            if (response.isSuccess() && response.getData() != null) {
                FileVO file = response.getData();
                ContractVersionHistoryRespDTO.FileInfoDTO fileInfo = new ContractVersionHistoryRespDTO.FileInfoDTO();
                fileInfo.setFileId(file.getFileId().toString());
                fileInfo.setFileName(file.getFileName());
                fileInfo.setFileType(file.getFileType());
                fileInfo.setCreateTime(formatTimeField(file.getCreateTime()));
                
                // 设置fileKey：优先从file_history表获取
                String fileKey = getFileKey(fileId, fileHistoryVersion, file.getFileKey());
                fileInfo.setFileKey(fileKey);
                
                // 设置fileVersion：优先使用contract_file中的file_history_version，否则查询file_history表的最低版本
                Integer fileVersion = null;
                if (fileHistoryVersion != null) {
                    // 使用contract_file表中的file_history_version
                    fileVersion = fileHistoryVersion;
                    log.info("使用contract_file中的file_history_version作为fileVersion，文件ID: {}, 版本: {}", fileId, fileVersion);
                } else {
                    // 查询file_history表中的最低版本
                    fileVersion = getMinFileHistoryVersion(fileId);
                    if (fileVersion != null) {
                        log.info("使用file_history表中的最低版本作为fileVersion，文件ID: {}, 版本: {}", fileId, fileVersion);
                    } else {
                        log.info("未找到file_history版本数据，fileVersion保持为null，文件ID: {}", fileId);
                    }
                }
                fileInfo.setFileVersion(fileVersion);
                
                return fileInfo;
            }
        } catch (Exception e) {
            log.error("获取文件信息失败，文件ID: {}", fileId, e);
        }
        
        return null;
    }
    
    /**
     * 获取文件Key
     */
    private String getFileKey(Long fileId, Integer fileHistoryVersion, String defaultFileKey) {
        // 如果fileHistoryVersion不为空，从file_history表查询
        if (fileHistoryVersion != null) {
            try {
                FileHistory history = fileHistoryMapper.selectOne(
                        new LambdaQueryWrapper<FileHistory>()
                                .eq(FileHistory::getFileId, fileId)
                                .eq(FileHistory::getVersion, fileHistoryVersion)
                );
                
                if (history != null && history.getFileKey() != null) {
                    return history.getFileKey();
                }
            } catch (Exception e) {
                log.warn("从file_history表获取fileKey失败，使用默认值，文件ID: {}, 版本: {}", fileId, fileHistoryVersion, e);
            }
        }
        
        // 如果没有file_history_version或查询失败，使用file_info表的fileKey
        return defaultFileKey;
    }
    
    /**
     * 获取file_history表中指定文件的最低版本号
     * 
     * @param fileId 文件ID
     * @return 最低版本号（整数形式），如果没有数据或version为空则返回null
     */
    private Integer getMinFileHistoryVersion(Long fileId) {
        try {
            FileHistory minHistory = fileHistoryMapper.selectOne(
                    new LambdaQueryWrapper<FileHistory>()
                            .eq(FileHistory::getFileId, fileId)
                            .isNotNull(FileHistory::getVersion) // 只查询version不为空的记录
                            .orderByAsc(FileHistory::getVersion) // 按版本号升序排列，取最小值
                            .last("LIMIT 1")
            );
            
            if (minHistory != null && minHistory.getVersion() != null) {
                log.info("找到文件历史最低版本，文件ID: {}, 版本号: {}", fileId, minHistory.getVersion());
                return minHistory.getVersion();
            } else {
                log.info("未找到文件历史版本数据或version为空，文件ID: {}", fileId);
                return null;
            }
        } catch (Exception e) {
            log.error("获取文件历史最低版本失败，文件ID: {}", fileId, e);
            return null;
        }
    }
    
    /**
     * 格式化时间字段
     */
    private String formatTimeField(Object timeValue) {
        if (timeValue == null) {
            return null;
        }
        
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            
            if (timeValue instanceof Long) {
                // 时间戳转换
                Long timestamp = (Long) timeValue;
                java.time.LocalDateTime dateTime = java.time.LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(timestamp), 
                        java.time.ZoneId.systemDefault()
                );
                return dateTime.format(formatter);
            } else if (timeValue instanceof LocalDateTime) {
                // LocalDateTime直接格式化
                return ((LocalDateTime) timeValue).format(formatter);
            } else if (timeValue instanceof java.util.Date) {
                // Date转换
                java.util.Date date = (java.util.Date) timeValue;
                java.time.LocalDateTime dateTime = date.toInstant()
                        .atZone(java.time.ZoneId.systemDefault())
                        .toLocalDateTime();
                return dateTime.format(formatter);
            } else {
                // 其他类型尝试转换为字符串
                return timeValue.toString();
            }
        } catch (Exception e) {
            log.warn("时间格式化失败，原值: {}, 类型: {}", timeValue, timeValue.getClass().getName(), e);
            return timeValue.toString();
        }
    }
    
    /**
     * 格式化LocalDateTime
     */
    private String formatDateTime(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteNegotiationByContractId(Integer contractId) {
        log.info("开始删除合同协商，合同ID: {}", contractId);
        
        // 1. 根据合同ID查询协商实例
        ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                        .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
        );
        
        if (instance == null) {
            log.warn("未找到合同协商实例，合同ID: {}", contractId);
            return false;
        }
        
        Integer instanceId = instance.getId();
        log.info("找到协商实例，实例ID: {}, 协商状态: {}", instanceId, instance.getNegotiationStatus());
        
        // 2. 删除协商参与者表数据
        int participantDeleteCount = contractNegotiationParticipantMapper.delete(
                new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                        .eq(ContractNegotiationParticipantEntity::getInstanceId, instanceId)
        );
        log.info("删除协商参与者记录数: {}", participantDeleteCount);
        
        // 3. 删除协商节点实例表数据
        int nodeInstanceDeleteCount = contractNegotiationNodeInstanceMapper.delete(
                new LambdaQueryWrapper<ContractNegotiationNodeInstanceEntity>()
                        .eq(ContractNegotiationNodeInstanceEntity::getInstanceId, instanceId)
        );
        log.info("删除协商节点实例记录数: {}", nodeInstanceDeleteCount);
        
        // 4. 删除协商实例表数据
        int instanceDeleteCount = contractNegotiationInstanceMapper.deleteById(instanceId);
        log.info("删除协商实例记录数: {}", instanceDeleteCount);
        
        if (instanceDeleteCount > 0) {
            log.info("成功删除合同协商，合同ID: {}, 实例ID: {}", contractId, instanceId);
            return true;
        } else {
            log.error("删除协商实例失败，合同ID: {}, 实例ID: {}", contractId, instanceId);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public NegotiationAnnouncementRespDTO getNegotiationAnnouncement() {
        try {
            log.info("开始获取协商公告配置");

            // 获取当前用户的系统租户键
            UserInfo currentUser = AuthUtil.getCurrentUser();
            if (currentUser == null || currentUser.getSysTenantKey() == null) {
                log.error("无法获取当前用户的系统租户键");
                throw new RuntimeException("无法获取当前用户信息");
            }

            String sysTenantKey = currentUser.getSysTenantKey();
            log.info("当前用户的系统租户键: {}", sysTenantKey);

            // 查询协商公告配置
            ContractNegotiationManagementEntity managementConfig = contractNegotiationManagementMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationManagementEntity>()
                            .eq(ContractNegotiationManagementEntity::getSysTenantKey, sysTenantKey)
                            .orderByDesc(ContractNegotiationManagementEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (managementConfig == null) {
                log.warn("未找到系统租户键为 {} 的协商公告配置，创建默认配置", sysTenantKey);
                
                // 创建默认配置记录
                ContractNegotiationManagementEntity defaultEntity = new ContractNegotiationManagementEntity();
                defaultEntity.setSysTenantKey(sysTenantKey);
                defaultEntity.setNegotiationAnnouncementEnabled(false); // 对应 0
                defaultEntity.setNegotiationAnnouncementTextEnabled(false); // 对应 0
                defaultEntity.setNegotiationAnnouncementText(null);
                defaultEntity.setCreatedAt(LocalDateTime.now());
                defaultEntity.setUpdatedAt(LocalDateTime.now());
                
                // 插入默认记录
                contractNegotiationManagementMapper.insert(defaultEntity);
                log.info("成功插入默认协商公告配置 - 系统租户键: {}", sysTenantKey);
                
                // 返回默认配置
                NegotiationAnnouncementRespDTO defaultConfig = new NegotiationAnnouncementRespDTO();
                defaultConfig.setNegotiationAnnouncementEnabled(false);
                defaultConfig.setNegotiationAnnouncementTextEnabled(false);
                defaultConfig.setNegotiationAnnouncementText("");
                return defaultConfig;
            }

            // 构建返回结果
            NegotiationAnnouncementRespDTO result = new NegotiationAnnouncementRespDTO();
            result.setNegotiationAnnouncementEnabled(managementConfig.getNegotiationAnnouncementEnabled());
            result.setNegotiationAnnouncementTextEnabled(managementConfig.getNegotiationAnnouncementTextEnabled());
            result.setNegotiationAnnouncementText(managementConfig.getNegotiationAnnouncementText());

            log.info("成功获取协商公告配置 - 系统租户键: {}, 公告必填启用: {}, 提示文本启用: {}",
                    sysTenantKey,
                    result.getNegotiationAnnouncementEnabled(),
                    result.getNegotiationAnnouncementTextEnabled());

            return result;

        } catch (Exception e) {
            log.error("获取协商公告配置失败", e);
            // 返回默认配置
            NegotiationAnnouncementRespDTO defaultConfig = new NegotiationAnnouncementRespDTO();
            defaultConfig.setNegotiationAnnouncementEnabled(false);
            defaultConfig.setNegotiationAnnouncementTextEnabled(false);
            defaultConfig.setNegotiationAnnouncementText("");
            return defaultConfig;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean inviteNegotiation(InviteNegotiationReqDTO dto) {
        try {
            log.info("开始邀请用户参与协商，合同ID: {}, 被邀请用户ID: {}", dto.getContractId(), dto.getInvitedUserId());

            // 1. 查询协商实例
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, dto.getContractId())
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus,
                                Arrays.asList(
                                    NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.PENDING_NEGOTIATION.getCode()
                                ))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (instance == null) {
                log.warn("未找到可邀请的协商实例，合同ID: {}", dto.getContractId());
                return false;
            }

            log.info("找到协商实例，实例ID: {}, 状态: {}", instance.getId(), instance.getNegotiationStatus());

            // 2. 检查用户是否已经是参与者
            ContractNegotiationParticipantEntity existingParticipant = contractNegotiationParticipantMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                            .eq(ContractNegotiationParticipantEntity::getEmployeeId, dto.getInvitedUserId())
            );

            if (existingParticipant != null) {
                log.info("用户已经是协商参与者，用户ID: {}", dto.getInvitedUserId());
                return false;
            }

            // 3. 获取当前用户信息并判断身份
            UserInfo currentUser = AuthUtil.getCurrentUser();
            if (currentUser == null) {
                log.warn("无法获取当前用户信息");
                return false;
            }

            Long currentUserId = currentUser.getId();
            log.info("当前邀请用户ID: {}", currentUserId);

            // 4. 查询当前用户在协商中的参与者信息（如果用户在多个节点，选择第一个）
            List<ContractNegotiationParticipantEntity> currentUserParticipants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                            .eq(ContractNegotiationParticipantEntity::getEmployeeId, currentUserId)
                            .orderBy(true, true, ContractNegotiationParticipantEntity::getId) // 按ID排序，确保结果稳定
            );

            ContractNegotiationParticipantEntity currentUserParticipant = null;
            if (!currentUserParticipants.isEmpty()) {
                currentUserParticipant = currentUserParticipants.get(0); // 选择第一个

                if (currentUserParticipants.size() > 1) {
                    log.info("当前用户在多个协商节点中，共 {} 个节点，选择第一个节点进行邀请，节点实例ID: {}",
                            currentUserParticipants.size(), currentUserParticipant.getNodeInstanceId());

                    // 打印所有参与的节点信息
                    for (ContractNegotiationParticipantEntity participant : currentUserParticipants) {
                        log.info("用户参与的节点: 节点实例ID={}, 参与者类型={}",
                                participant.getNodeInstanceId(), participant.getParticipantType());
                    }
                } else {
                    log.info("当前用户在单个协商节点中，节点实例ID: {}", currentUserParticipant.getNodeInstanceId());
                }
            }

            // 5. 根据当前用户身份决定邀请类型
            String participantType;
            Integer nodeInstanceId = null;
            Long flwTaskId = null;

            if (currentUserParticipant != null) {
                String currentUserType = currentUserParticipant.getParticipantType();

                if ("NODE_PARTICIPANT".equals(currentUserType)) {
                    // 当前用户是节点参与者，邀请的用户也作为节点参与者
                    participantType = "NODE_PARTICIPANT";
                    nodeInstanceId = currentUserParticipant.getNodeInstanceId();

                    log.info("当前用户是节点参与者，节点实例ID: {}, 将被邀请用户也设为节点参与者", nodeInstanceId);

                    // 6. 查找当前用户在流程中的任务ID
                    if (instance.getProcessInstanceId() != null) {
                        flwTaskId = findCurrentUserFlwTaskId(instance.getProcessInstanceId(), currentUserId);
                        log.info("找到当前用户的流程任务ID: {}", flwTaskId);
                    }
                } else if ("OBSERVER".equals(currentUserType)) {
                    // 当前用户是观察者，邀请的用户也作为观察者
                    participantType = "OBSERVER";
                    log.info("当前用户是观察者，将被邀请用户也设为观察者");
                } else {
                    // 其他类型的参与者，默认邀请为观察者
                    participantType = "OBSERVER";
                    log.info("当前用户参与者类型: {}, 将被邀请用户设为观察者", currentUserType);
                }
            } else {
                // 当前用户不是协商参与者，检查是否为协商发起者
                if (instance.getApplicantId() != null && instance.getApplicantId().equals(currentUserId)) {
                    // 当前用户是协商发起者，允许邀请其他用户作为观察者
                    participantType = "OBSERVER";
                    log.info("当前用户是协商发起者，允许邀请其他用户作为观察者，发起者ID: {}", currentUserId);
                } else {
                    // 当前用户既不是协商参与者也不是发起者，不允许邀请
                    log.warn("当前用户既不是协商参与者也不是协商发起者，无权邀请其他用户，用户ID: {}", currentUserId);
                    return false;
                }
            }

            // 7. 创建新的参与者记录
            ContractNegotiationParticipantEntity participant = new ContractNegotiationParticipantEntity()
                    .setInstanceId(instance.getId())
                    .setNodeInstanceId(nodeInstanceId)
                    .setEmployeeId(dto.getInvitedUserId())
                    .setParticipantType(participantType)
                    .setIsViewed(false)
                    .setIsConfirmed(false)
                    .setCreatedAt(LocalDateTime.now())
                    .setUpdatedAt(LocalDateTime.now());

            contractNegotiationParticipantMapper.insert(participant);

            // 8. 如果是节点参与者且有流程任务ID，则动态追加审批人
            if ("NODE_PARTICIPANT".equals(participantType) && flwTaskId != null) {
                boolean appendResult = appendUserToDynamicAssignee(flwTaskId, dto.getInvitedUserId(), currentUserId);
                if (appendResult) {
                    log.info("成功将用户动态追加为审批人，用户ID: {}, 任务ID: {}", dto.getInvitedUserId(), flwTaskId);
                } else {
                    log.warn("动态追加用户审批人失败，用户ID: {}, 任务ID: {}", dto.getInvitedUserId(), flwTaskId);
                }
            }

            log.info("成功邀请用户参与协商，用户ID: {}, 参与者类型: {}", dto.getInvitedUserId(), participantType);

            // 9. 记录操作日志
            saveInviteOperationLog(dto.getContractId(), dto.getInvitedUserId());

            return true;

        } catch (Exception e) {
            log.error("邀请协商失败，合同ID: {}, 用户ID: {}", dto.getContractId(), dto.getInvitedUserId(), e);
            return false;
        }
    }

    /**
     * 查找当前用户在流程中的任务ID（如果用户在多个节点，返回第一个节点的任务ID）
     */
    private Long findCurrentUserFlwTaskId(Long flwInstanceId, Long userId) {
        try {
            log.info("开始查找用户 {} 在流程实例 {} 中的活动任务", userId, flwInstanceId);

            // 查询流程实例中当前用户的活动任务
            Optional<List<FlwTask>> activeTasksOpt = flowLongEngine.queryService().getActiveTasksByInstanceId(flwInstanceId);

            if (!activeTasksOpt.isPresent()) {
                log.warn("流程实例 {} 中没有活动任务", flwInstanceId);
                return null;
            }

            List<FlwTask> activeTasks = activeTasksOpt.get();
            log.info("流程实例 {} 中共有 {} 个活动任务", flwInstanceId, activeTasks.size());

            // 收集用户参与的所有任务
            List<FlwTask> userTasks = new ArrayList<>();

            for (FlwTask task : activeTasks) {
                log.debug("检查任务 {}: {}", task.getId(), task.getTaskName());

                // 查询任务的执行人
                List<FlwTaskActor> taskActors = flowLongEngine.queryService().getTaskActorsByTaskId(task.getId());
                log.debug("任务 {} 有 {} 个执行人", task.getId(), taskActors.size());

                for (FlwTaskActor actor : taskActors) {
                    log.debug("任务 {} 的执行人: {} ({})", task.getId(), actor.getActorName(), actor.getActorId());
                    if (userId.toString().equals(actor.getActorId())) {
                        userTasks.add(task);
                        log.info("找到用户 {} 的活动任务ID: {} ({})", userId, task.getId(), task.getTaskName());
                        break; // 找到该任务中的用户后，跳出内层循环
                    }
                }
            }

            if (userTasks.isEmpty()) {
                log.warn("未找到用户 {} 在流程实例 {} 中的活动任务", userId, flwInstanceId);

                // 打印所有任务的执行人信息，便于调试
                for (FlwTask task : activeTasks) {
                    List<FlwTaskActor> taskActors = flowLongEngine.queryService().getTaskActorsByTaskId(task.getId());
                    log.info("任务 {} ({}) 的所有执行人: {}", task.getId(), task.getTaskName(),
                        taskActors.stream().map(actor -> actor.getActorName() + "(" + actor.getActorId() + ")")
                            .reduce((a, b) -> a + ", " + b).orElse("无"));
                }

                return null;
            }

            // 如果用户在多个任务中，选择第一个任务（按任务ID排序）
            FlwTask selectedTask = userTasks.stream()
                    .min(Comparator.comparing(FlwTask::getId))
                    .orElse(userTasks.get(0));

            if (userTasks.size() > 1) {
                log.info("用户 {} 在多个审批节点中，共 {} 个任务，选择第一个任务ID: {} ({})",
                        userId, userTasks.size(), selectedTask.getId(), selectedTask.getTaskName());

                // 打印所有用户参与的任务信息
                for (FlwTask task : userTasks) {
                    log.info("用户参与的任务: {} - {} ({})", task.getId(), task.getTaskName(), task.getTaskKey());
                }
            } else {
                log.info("用户 {} 在单个审批节点中，任务ID: {} ({})",
                        userId, selectedTask.getId(), selectedTask.getTaskName());
            }

            return selectedTask.getId();

        } catch (Exception e) {
            log.error("查找用户流程任务失败，用户ID: {}, 流程实例ID: {}", userId, flwInstanceId, e);
            return null;
        }
    }

    /**
     * 将用户追加到流程任务节点
     */
    private boolean appendUserToFlowTask(Long taskId, Long userId) {
        try {
            log.info("开始追加用户到流程任务，用户ID: {}, 任务ID: {}", userId, taskId);

            // 查询被邀请用户信息
            SysUser invitedUser = sysUserService.getById(userId);
            if (invitedUser == null) {
                log.warn("被邀请用户不存在，用户ID: {}", userId);
                return false;
            }

            // 获取当前操作用户信息（邀请人）
            UserInfo currentUser = AuthUtil.getCurrentUser();
            if (currentUser == null) {
                log.warn("无法获取当前操作用户信息");
                return false;
            }

            // 创建流程任务执行人
            FlwTaskActor taskActor = new FlwTaskActor();
            taskActor.setTaskId(taskId);
            taskActor.setActorId(userId.toString());
            taskActor.setActorName(invitedUser.getRealName());
            taskActor.setActorType(ActorType.user.getValue());

            // 添加任务执行人 - 使用当前操作用户作为 FlowCreator
            List<FlwTaskActor> taskActors = Arrays.asList(taskActor);
            FlowCreator flowCreator = FlowCreator.of(currentUser.getId().toString(), currentUser.getRealName());

            log.info("准备调用 addTaskActor，任务ID: {}, 被邀请用户: {}, 操作人: {}",
                taskId, invitedUser.getRealName(), currentUser.getRealName());

            boolean result = flowLongEngine.taskService().addTaskActor(taskId, PerformType.countersign, taskActors, flowCreator);

            if (result) {
                log.info("成功将用户 {} 追加到流程任务 {}", userId, taskId);

                // 验证是否真的添加成功
                List<FlwTaskActor> taskActorList = flowLongEngine.queryService().getTaskActorsByTaskId(taskId);
                boolean found = taskActorList.stream().anyMatch(actor -> userId.toString().equals(actor.getActorId()));
                log.info("验证追加结果：任务 {} 的执行人列表中{}找到用户 {}", taskId, found ? "已" : "未", userId);

            } else {
                log.warn("追加用户 {} 到流程任务 {} 失败", userId, taskId);
            }

            return result;

        } catch (Exception e) {
            log.error("追加用户到流程任务失败，用户ID: {}, 任务ID: {}", userId, taskId, e);
            return false;
        }
    }

    /**
     * 将用户动态追加为审批人（使用动态分配机制）
     */
    private boolean appendUserToDynamicAssignee(Long taskId, Long invitedUserId, Long currentUserId) {
        try {
            log.info("开始动态追加用户为审批人，被邀请用户ID: {}, 任务ID: {}, 当前用户ID: {}",
                invitedUserId, taskId, currentUserId);

            // 查询被邀请用户信息
            SysUser invitedUser = sysUserService.getById(invitedUserId);
            if (invitedUser == null) {
                log.warn("被邀请用户不存在，用户ID: {}", invitedUserId);
                return false;
            }

            // 获取当前任务信息
            FlwTask flwTask = flowLongEngine.queryService().getTask(taskId);
            if (flwTask == null) {
                log.warn("任务不存在，任务ID: {}", taskId);
                return false;
            }

            // 获取当前任务的节点Key
            String currentNodeKey = flwTask.getTaskKey();
            log.info("当前任务节点Key: {}", currentNodeKey);

            // 获取流程实例和模型
            FlwInstance flwInstance = flowLongEngine.queryService().getInstance(flwTask.getInstanceId());
            if (flwInstance == null) {
                log.warn("流程实例不存在，实例ID: {}", flwTask.getInstanceId());
                return false;
            }

            ProcessModel processModel = flowLongEngine.runtimeService().getProcessModelByInstanceId(flwInstance.getId());
            NodeModel currentNode = processModel.getNode(currentNodeKey);

            if (currentNode == null) {
                log.warn("当前节点不存在，节点KEY: {}", currentNodeKey);
                return false;
            }

            // 获取当前节点的审批人列表
            List<NodeAssignee> currentAssignees = new ArrayList<>();
            if (currentNode.getNodeAssigneeList() != null) {
                currentAssignees.addAll(currentNode.getNodeAssigneeList());
            }

            // 检查用户是否已经是审批人
            boolean userAlreadyExists = currentAssignees.stream()
                    .anyMatch(assignee -> invitedUserId.toString().equals(assignee.getId()));

            if (userAlreadyExists) {
                log.info("用户 {} 已经是节点 {} 的审批人，无需重复添加", invitedUserId, currentNodeKey);
                return true;
            }

            // 添加新的审批人
            NodeAssignee newAssignee = new NodeAssignee();
            newAssignee.setId(invitedUserId.toString());
            newAssignee.setName(invitedUser.getRealName());
            currentAssignees.add(newAssignee);

            log.info("准备更新节点 {} 的审批人，总数: {}", currentNodeKey, currentAssignees.size());

            // 直接更新流程模型中的节点审批人列表
            currentNode.setNodeAssigneeList(currentAssignees);

            // 更新流程实例模型到数据库
            boolean updateResult = flowLongEngine.runtimeService().updateInstanceModelById(flwInstance.getId(), processModel);

            if (updateResult) {
                log.info("成功更新流程模型，用户 {} 已添加到节点 {} 的审批人列表", invitedUserId, currentNodeKey);

                // 将邀请人添加到当前任务的执行人表中（flw_task_actor）
                boolean addTaskActorResult = addUserToTaskActor(taskId, invitedUserId, invitedUser);

                if (addTaskActorResult) {
                    log.info("成功将用户 {} 添加到任务执行人表，任务ID: {}", invitedUserId, taskId);
                    return true;
                } else {
                    log.warn("添加用户到任务执行人表失败，但流程模型已更新，用户ID: {}, 任务ID: {}", invitedUserId, taskId);
                    // 即使添加到任务执行人表失败，流程模型已更新，仍然返回 true
                    return true;
                }
            } else {
                log.warn("更新流程模型失败，用户ID: {}, 节点: {}", invitedUserId, currentNodeKey);
                return false;
            }

        } catch (Exception e) {
            log.error("动态追加用户为审批人失败，用户ID: {}, 任务ID: {}", invitedUserId, taskId, e);
            return false;
        }
    }

    /**
     * 将用户添加到任务执行人表（flw_task_actor）
     */
    private boolean addUserToTaskActor(Long taskId, Long userId, SysUser user) {
        try {
            log.info("开始将用户添加到任务执行人表，用户ID: {}, 任务ID: {}", userId, taskId);

            // 检查用户是否已经是该任务的执行人
            List<FlwTaskActor> existingActors = flowLongEngine.queryService().getTaskActorsByTaskId(taskId);
            boolean userExists = existingActors.stream()
                    .anyMatch(actor -> userId.toString().equals(actor.getActorId()));

            if (userExists) {
                log.info("用户 {} 已经是任务 {} 的执行人，无需重复添加", userId, taskId);
                return true;
            }

            // 获取任务信息
            FlwTask flwTask = flowLongEngine.queryService().getTask(taskId);
            if (flwTask == null) {
                log.warn("任务不存在，任务ID: {}", taskId);
                return false;
            }

            // 直接向数据库添加任务执行人，避免触发引擎的自动完成逻辑
            FlwTaskActor taskActor = new FlwTaskActor();
            taskActor.setInstanceId(flwTask.getInstanceId());
            taskActor.setTaskId(taskId);
            taskActor.setActorId(userId.toString());
            taskActor.setActorName(user.getRealName());
            taskActor.setActorType(0); // 0表示用户类型
            taskActor.setWeight(1); // 默认权重
            taskActor.setTenantId(flwTask.getTenantId());

            // 直接插入到数据库，不通过引擎服务
            // MyBatis-Plus 会自动生成ID，不需要手动设置

            // 通过 MyBatis-Plus 直接插入
            int insertResult = flwTaskActorMapper.insert(taskActor);
            boolean result = insertResult > 0;

            if (result) {
                log.info("成功将用户 {} ({}) 直接添加为任务 {} 的执行人（避免触发自动完成）", userId, user.getRealName(), taskId);
                return true;
            } else {
                log.warn("直接添加用户到任务执行人表失败，用户ID: {}, 任务ID: {}", userId, taskId);
                return false;
            }

        } catch (Exception e) {
            log.error("添加用户到任务执行人表时发生异常，用户ID: {}, 任务ID: {}", userId, taskId, e);
            return false;
        }
    }

    /**
     * 创建追加节点模型
     */
    private NodeModel createAppendNodeModel(SysUser invitedUser, UserInfo currentUser) {
        // 生成唯一的节点Key
        String nodeKey = "append_" + invitedUser.getId() + "_" + System.currentTimeMillis();
        String nodeName = "协商邀请-" + invitedUser.getRealName();

        log.info("创建追加节点模型，节点Key: {}, 节点名称: {}", nodeKey, nodeName);

        NodeModel nodeModel = new NodeModel();
        nodeModel.setNodeName(nodeName);
        nodeModel.setNodeKey(nodeKey);
        nodeModel.setType(1); // 审批节点
        nodeModel.setSetType(1); // 指定成员
        nodeModel.setExamineMode(PerformType.countersign.getValue()); // 会签模式

        // 创建节点分配人
        NodeAssignee nodeAssignee = new NodeAssignee();
        nodeAssignee.setId(invitedUser.getId().toString());
        nodeAssignee.setName(invitedUser.getRealName());
        // 注意：NodeAssignee 没有 type 字段，类型信息在 NodeModel 的 setType 中设置

        // 设置节点分配人列表
        nodeModel.setNodeAssigneeList(Collections.singletonList(nodeAssignee));

        log.info("追加节点模型创建完成，节点: {} ({}), 审批人: {} ({})",
            nodeName, nodeKey, invitedUser.getRealName(), invitedUser.getId());

        return nodeModel;
    }

    /**
     * 保存邀请操作日志
     */
    private void saveInviteOperationLog(Integer contractId, Long invitedUserId) {
        try {
            // 获取当前用户ID
            UserInfo currentUser = AuthUtil.getCurrentUser();
            if (currentUser == null || currentUser.getId() == null) {
                log.warn("无法获取当前用户信息，跳过操作日志记录");
                return;
            }

            Long currentUserId = currentUser.getId();

            // 构建ext_data JSON字符串
            Map<String, Object> extData = new HashMap<>();
            extData.put("participantIds", Arrays.asList(invitedUserId.toString()));
            String extDataJson = JacksonUtils.toJson(extData);

            // 构建操作日志记录
            ContractOperationLog operationLog = ContractOperationLog.builder()
                    .contractId(contractId.longValue())
                    .flowType(WorkFlowTypeEnums.NEGOTIATION_WORKFLOW.getCode())
                    .actionType(ActionTypeEnums.INVITE_NEGOTIATOR.getCode())
                    .sourceType(SourceTypeEnums.USER.getCode())
                    .userId(currentUserId)
                    .actionTime(new Date())
                    .extData(extDataJson)
                    .remark("邀请")
                    .build();

            // 保存操作日志
            contractOperationLogMapper.insert(operationLog);

            log.info("保存邀请操作日志成功，合同ID: {}, 当前用户ID: {}, 被邀请用户ID: {}",
                    contractId, currentUserId, invitedUserId);

        } catch (Exception e) {
            log.error("保存邀请操作日志失败，合同ID: {}, 被邀请用户ID: {}", contractId, invitedUserId, e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean exitNegotiation(Integer contractId, Long userId) {
        try {
            log.info("开始退出协商，合同ID: {}, 用户ID: {}", contractId, userId);

            // 1. 查询协商实例
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus,
                                Arrays.asList(
                                    NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.PENDING_NEGOTIATION.getCode()
                                ))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (instance == null) {
                log.warn("未找到可退出的协商实例，合同ID: {}", contractId);
                return false;
            }

            log.info("找到协商实例，实例ID: {}, 状态: {}", instance.getId(), instance.getNegotiationStatus());

            // 2. 检查用户是否是协商参与者
            List<ContractNegotiationParticipantEntity> userParticipants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                            .eq(ContractNegotiationParticipantEntity::getEmployeeId, userId)
            );

            if (userParticipants.isEmpty()) {
                log.warn("用户不是协商参与者，无法退出，合同ID: {}, 用户ID: {}", contractId, userId);
                return false;
            }

            // 3. 检查用户是否是某个节点的唯一审批人
            boolean isUniqueApprover = checkIfUniqueApprover(instance, userId);
            if (isUniqueApprover) {
                log.warn("用户是某个节点的唯一审批人，无法退出协商，合同ID: {}, 用户ID: {}", contractId, userId);
                return false;
            }

            // 4. 如果有流程实例ID，从 flw_task_actor 表移除用户并更新流程模型JSON
            if (instance.getProcessInstanceId() != null) {
                removeUserFromFlwTaskActor(instance.getProcessInstanceId(), userId);
                updateProcessModelRemoveUser(instance.getProcessInstanceId(), userId);
            }

            // 5. 从 contract_negotiation_participant 表移除用户
            int removedCount = contractNegotiationParticipantMapper.delete(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                            .eq(ContractNegotiationParticipantEntity::getEmployeeId, userId)
            );

            log.info("从协商参与者表移除用户记录数: {}", removedCount);

            log.info("退出协商成功，合同ID: {}, 用户ID: {}", contractId, userId);
            return true;

        } catch (Exception e) {
            log.error("退出协商失败，合同ID: {}, 用户ID: {}", contractId, userId, e);
            return false;
        }
    }

    /**
     * 检查用户是否是某个节点的唯一审批人
     */
    private boolean checkIfUniqueApprover(ContractNegotiationInstanceEntity instance, Long userId) {
        try {
            // 获取用户参与的所有节点
            List<ContractNegotiationParticipantEntity> userParticipants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                            .eq(ContractNegotiationParticipantEntity::getEmployeeId, userId)
                            .eq(ContractNegotiationParticipantEntity::getParticipantType, "NODE_PARTICIPANT")
            );

            // 检查每个节点是否有其他审批人
            for (ContractNegotiationParticipantEntity participant : userParticipants) {
                if (participant.getNodeInstanceId() != null) {
                    // 查询该节点的所有审批人
                    List<ContractNegotiationParticipantEntity> nodeParticipants = contractNegotiationParticipantMapper.selectList(
                            new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                                    .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                                    .eq(ContractNegotiationParticipantEntity::getNodeInstanceId, participant.getNodeInstanceId())
                                    .eq(ContractNegotiationParticipantEntity::getParticipantType, "NODE_PARTICIPANT")
                    );

                    // 如果该节点只有当前用户一个审批人，则不能退出
                    if (nodeParticipants.size() == 1 && nodeParticipants.get(0).getEmployeeId().equals(userId)) {
                        log.warn("用户是节点实例ID: {} 的唯一审批人，无法退出", participant.getNodeInstanceId());
                        return true;
                    }

                    // 如果流程实例存在，还需要检查 flw_task_actor 表
                    if (instance.getProcessInstanceId() != null) {
                        boolean isUniqueInFlwTaskActor = checkUniqueInFlwTaskActor(instance.getProcessInstanceId(), userId);
                        if (isUniqueInFlwTaskActor) {
                            log.warn("用户是流程实例ID: {} 的某个任务的唯一审批人，无法退出", instance.getProcessInstanceId());
                            return true;
                        }
                    }
                }
            }

            return false;

        } catch (Exception e) {
            log.error("检查用户是否是唯一审批人失败，实例ID: {}, 用户ID: {}", instance.getId(), userId, e);
            // 出于安全考虑，如果检查失败，默认认为是唯一审批人
            return true;
        }
    }

    /**
     * 检查用户是否是流程实例中某个任务的唯一审批人
     */
    private boolean checkUniqueInFlwTaskActor(Long processInstanceId, Long userId) {
        try {
            // 获取流程实例的所有活跃任务
            List<FlwTask> activeTasks = flowLongEngine.queryService().getTasksByInstanceId(processInstanceId);

            if (activeTasks == null || activeTasks.isEmpty()) {
                return false;
            }

            // 检查每个任务的参与者
            for (FlwTask task : activeTasks) {
                var taskActorsOpt = flowLongEngine.queryService().getActiveTaskActorsByTaskId(task.getId());
                if (taskActorsOpt.isPresent()) {
                    List<FlwTaskActor> taskActors = taskActorsOpt.get();

                    // 检查当前用户是否是任务参与者
                    boolean isUserInTask = taskActors.stream()
                            .anyMatch(actor -> String.valueOf(userId).equals(actor.getActorId()));

                    if (isUserInTask) {
                        // 检查是否是唯一的用户类型参与者
                        List<FlwTaskActor> userTypeActors = taskActors.stream()
                                .filter(actor -> actor.getActorType() == 0) // 0表示用户类型
                                .collect(Collectors.toList());

                        if (userTypeActors.size() == 1 && String.valueOf(userId).equals(userTypeActors.get(0).getActorId())) {
                            log.warn("用户是任务ID: {} 的唯一用户类型审批人", task.getId());
                            return true;
                        }
                    }
                }
            }

            return false;

        } catch (Exception e) {
            log.error("检查流程任务唯一审批人失败，流程实例ID: {}, 用户ID: {}", processInstanceId, userId, e);
            return true; // 出于安全考虑，检查失败时默认认为是唯一审批人
        }
    }

    /**
     * 从 flw_task_actor 表移除用户
     */
    private void removeUserFromFlwTaskActor(Long processInstanceId, Long userId) {
        try {
            // 获取流程实例的所有活跃任务
            List<FlwTask> activeTasks = flowLongEngine.queryService().getTasksByInstanceId(processInstanceId);

            if (activeTasks == null || activeTasks.isEmpty()) {
                log.info("流程实例没有活跃任务，跳过 flw_task_actor 表清理，流程实例ID: {}", processInstanceId);
                return;
            }

            int removedCount = 0;

            // 从每个任务中移除用户
            for (FlwTask task : activeTasks) {
                var taskActorsOpt = flowLongEngine.queryService().getActiveTaskActorsByTaskId(task.getId());
                if (taskActorsOpt.isPresent()) {
                    List<FlwTaskActor> taskActors = taskActorsOpt.get();

                    // 找到当前用户的任务参与者记录
                    List<FlwTaskActor> userActors = taskActors.stream()
                            .filter(actor -> String.valueOf(userId).equals(actor.getActorId()))
                            .collect(Collectors.toList());

                    // 删除用户的任务参与者记录
                    for (FlwTaskActor actor : userActors) {
                        if (actor.getId() != null) {
                            flwTaskActorMapper.deleteById(actor.getId());
                            removedCount++;
                            log.info("从 flw_task_actor 表移除用户记录，记录ID: {}, 任务ID: {}, 用户ID: {}",
                                    actor.getId(), task.getId(), userId);
                        }
                    }
                }
            }

            log.info("从 flw_task_actor 表移除用户记录总数: {}", removedCount);

        } catch (Exception e) {
            log.error("从 flw_task_actor 表移除用户失败，流程实例ID: {}, 用户ID: {}", processInstanceId, userId, e);
        }
    }

    /**
     * 更新流程模型JSON，移除指定用户
     */
    private void updateProcessModelRemoveUser(Long processInstanceId, Long userId) {
        try {
            // 查询流程扩展实例
            FlwExtInstance extInstance = flwExtInstanceMapper.selectById(processInstanceId);
            if (extInstance == null) {
                log.warn("未找到流程扩展实例，流程实例ID: {}", processInstanceId);
                return;
            }

            String modelContent = extInstance.getModelContent();
            if (modelContent == null || modelContent.trim().isEmpty()) {
                log.warn("流程模型内容为空，流程实例ID: {}", processInstanceId);
                return;
            }

            // 解析JSON并移除用户
            String updatedModelContent = removeUserFromModelContent(modelContent, userId);

            // 更新数据库
            if (!modelContent.equals(updatedModelContent)) {
                extInstance.setModelContent(updatedModelContent);
                flwExtInstanceMapper.updateById(extInstance);
                log.info("成功更新流程模型JSON，移除用户ID: {}", userId);
            } else {
                log.info("流程模型JSON中未找到用户信息，无需更新，用户ID: {}", userId);
            }

        } catch (Exception e) {
            log.error("更新流程模型JSON失败，流程实例ID: {}, 用户ID: {}", processInstanceId, userId, e);
        }
    }

    /**
     * 从流程模型JSON中移除指定用户
     */
    private String removeUserFromModelContent(String modelContent, Long userId) {
        try {
            // 解析JSON
            Map<String, Object> modelMap = JacksonUtils.readMap(modelContent);
            if (modelMap == null) {
                return modelContent;
            }

            // 递归处理节点配置
            Object nodeConfig = modelMap.get("nodeConfig");
            if (nodeConfig instanceof Map) {
                removeUserFromNode((Map<String, Object>) nodeConfig, userId);
            }

            // 返回更新后的JSON
            return JacksonUtils.toJson(modelMap);

        } catch (Exception e) {
            log.error("解析流程模型JSON失败", e);
            return modelContent;
        }
    }

    /**
     * 递归移除节点中的用户信息
     */
    private void removeUserFromNode(Map<String, Object> node, Long userId) {
        if (node == null) {
            return;
        }

        try {
            // 移除 nodeAssigneeList 中的用户
            Object nodeAssigneeList = node.get("nodeAssigneeList");
            if (nodeAssigneeList instanceof List) {
                List<Map<String, Object>> assigneeList = (List<Map<String, Object>>) nodeAssigneeList;
                assigneeList.removeIf(assignee -> {
                    Object id = assignee.get("id");
                    return id != null && userId.toString().equals(id.toString());
                });
            }

            // 移除 nodeCandidate.assignees 中的用户
            Object nodeCandidate = node.get("nodeCandidate");
            if (nodeCandidate instanceof Map) {
                Map<String, Object> candidateMap = (Map<String, Object>) nodeCandidate;
                Object assignees = candidateMap.get("assignees");
                if (assignees instanceof List) {
                    List<Map<String, Object>> assigneesList = (List<Map<String, Object>>) assignees;
                    assigneesList.removeIf(assignee -> {
                        Object id = assignee.get("id");
                        return id != null && userId.toString().equals(id.toString());
                    });
                }
            }

            // 处理子节点
            Object childNode = node.get("childNode");
            if (childNode instanceof Map) {
                removeUserFromNode((Map<String, Object>) childNode, userId);
            }

            // 处理条件分支节点
            Object conditionNodes = node.get("conditionNodes");
            if (conditionNodes instanceof List) {
                List<Map<String, Object>> conditionList = (List<Map<String, Object>>) conditionNodes;
                for (Map<String, Object> conditionNode : conditionList) {
                    removeUserFromNode(conditionNode, userId);
                }
            }

        } catch (Exception e) {
            log.error("移除节点用户信息失败", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelNegotiation(Integer contractId) {
        try {
            log.info("开始取消协商，合同ID: {}", contractId);

            // 1. 查询协商实例
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus,
                                Arrays.asList(
                                    NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.PENDING_NEGOTIATION.getCode()
                                ))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (instance == null) {
                log.warn("未找到可取消的协商实例，合同ID: {}", contractId);
                return false;
            }

            log.info("找到协商实例，实例ID: {}, 当前状态: {}", instance.getId(), instance.getNegotiationStatus());

            // 2. 更新协商状态为NEGOTIATION_CANCELED
            instance.setNegotiationStatus(NegotiationStatusEnum.NEGOTIATION_CANCELED.getCode());
            instance.setUpdatedAt(LocalDateTime.now());
            contractNegotiationInstanceMapper.updateById(instance);

            log.info("协商状态已更新为NEGOTIATION_CANCELED，实例ID: {}", instance.getId());

            // 3. 如果有流程实例ID，撤销审批流程
            if (instance.getProcessInstanceId() != null) {
                log.info("开始撤销审批流程，流程实例ID: {}", instance.getProcessInstanceId());

                ProcessApprovalDTO revokeDto = new ProcessApprovalDTO();
                revokeDto.setInstanceId(instance.getProcessInstanceId());
                revokeDto.setContent("协商取消");
                revokeDto.setTermination(true); // 设置为终止流程

                FlowCreator flowCreator = FlowHelper.getFlowCreator();
                boolean revokeResult = flwProcessTaskService.revoke(revokeDto, flowCreator);

                if (revokeResult) {
                    log.info("审批流程撤销成功，流程实例ID: {}", instance.getProcessInstanceId());
                } else {
                    log.warn("审批流程撤销失败，流程实例ID: {}", instance.getProcessInstanceId());
                }
            } else {
                log.info("协商实例没有关联流程实例，跳过流程撤销，实例ID: {}", instance.getId());
            }

            log.info("取消协商成功，合同ID: {}, 协商实例ID: {}", contractId, instance.getId());
            return true;

        } catch (Exception e) {
            log.error("取消协商失败，合同ID: {}", contractId, e);
            return false;
        }
    }

    @Override
    public Page<NegotiationAnnouncementListRespDTO> getNegotiationAnnouncementList(NegotiationAnnouncementListReqDTO dto) {
        try {
            log.info("开始获取协商公告配置列表，分页参数：页码={}, 每页大小={}", dto.getPageNum(), dto.getPageSize());

            // 构建分页对象
            Page<ContractNegotiationManagementEntity> page = new Page<>(dto.getPageNum(), dto.getPageSize());

            // 构建查询条件
            LambdaQueryWrapper<ContractNegotiationManagementEntity> queryWrapper = new LambdaQueryWrapper<>();
            
            // 添加筛选条件
            if (dto.getSysTenantKey() != null && !dto.getSysTenantKey().trim().isEmpty()) {
                queryWrapper.eq(ContractNegotiationManagementEntity::getSysTenantKey, dto.getSysTenantKey());
            }
            if (dto.getNegotiationAnnouncementEnabled() != null) {
                queryWrapper.eq(ContractNegotiationManagementEntity::getNegotiationAnnouncementEnabled, dto.getNegotiationAnnouncementEnabled());
            }
            if (dto.getNegotiationAnnouncementTextEnabled() != null) {
                queryWrapper.eq(ContractNegotiationManagementEntity::getNegotiationAnnouncementTextEnabled, dto.getNegotiationAnnouncementTextEnabled());
            }
            
            // 按创建时间倒序排列
            queryWrapper.orderByDesc(ContractNegotiationManagementEntity::getCreatedAt);

            // 执行分页查询
            Page<ContractNegotiationManagementEntity> managementPage = contractNegotiationManagementMapper.selectPage(page, queryWrapper);

            // 构建返回结果的分页对象
            Page<NegotiationAnnouncementListRespDTO> resultPage = new Page<>();
            resultPage.setCurrent(managementPage.getCurrent());
            resultPage.setSize(managementPage.getSize());
            resultPage.setTotal(managementPage.getTotal());
            resultPage.setPages(managementPage.getPages());

            if (managementPage.getRecords().isEmpty()) {
                log.info("未找到任何协商公告配置记录");
                resultPage.setRecords(new ArrayList<>());
                return resultPage;
            }

            // 获取所有的系统租户键
            Set<String> sysTenantKeys = managementPage.getRecords().stream()
                    .map(ContractNegotiationManagementEntity::getSysTenantKey)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            // 查询对应的系统租户名称
            Map<String, String> tenantNameMap = new HashMap<>();
            if (!sysTenantKeys.isEmpty()) {
                List<com.aizuda.boot.modules.system.entity.SysDepartment> departments = sysDepartmentService.list(
                        new LambdaQueryWrapper<com.aizuda.boot.modules.system.entity.SysDepartment>()
                                .in(com.aizuda.boot.modules.system.entity.SysDepartment::getSysTenantKey, sysTenantKeys)
                                .and(wrapper -> wrapper
                                        .eq(com.aizuda.boot.modules.system.entity.SysDepartment::getPid, 0)
                                        .or()
                                        .eq(com.aizuda.boot.modules.system.entity.SysDepartment::getIndependentFlag, 1)
                                )
                );

                // 构建租户键到租户名称的映射
                tenantNameMap = departments.stream()
                        .collect(Collectors.toMap(
                                com.aizuda.boot.modules.system.entity.SysDepartment::getSysTenantKey,
                                com.aizuda.boot.modules.system.entity.SysDepartment::getName,
                                (existing, replacement) -> existing // 如果有重复的key，保留第一个
                        ));
            }

            // 构建返回结果
            List<NegotiationAnnouncementListRespDTO> resultList = new ArrayList<>();
            for (ContractNegotiationManagementEntity entity : managementPage.getRecords()) {
                NegotiationAnnouncementListRespDTO respDTO = new NegotiationAnnouncementListRespDTO();
                respDTO.setId(entity.getId());
                respDTO.setNegotiationAnnouncementEnabled(entity.getNegotiationAnnouncementEnabled());
                respDTO.setNegotiationAnnouncementTextEnabled(entity.getNegotiationAnnouncementTextEnabled());
                respDTO.setNegotiationAnnouncementText(entity.getNegotiationAnnouncementText());
                respDTO.setSysTenantKey(entity.getSysTenantKey());
                respDTO.setSysTenantName(tenantNameMap.get(entity.getSysTenantKey()));
                respDTO.setCreatedAt(entity.getCreatedAt());
                respDTO.setUpdatedAt(entity.getUpdatedAt());
                resultList.add(respDTO);
            }

            resultPage.setRecords(resultList);

            log.info("成功获取协商公告配置列表，共 {} 条记录，总记录数 {}", resultList.size(), resultPage.getTotal());
            return resultPage;

        } catch (Exception e) {
            log.error("获取协商公告配置列表失败", e);
            Page<NegotiationAnnouncementListRespDTO> emptyPage = new Page<>();
            emptyPage.setRecords(new ArrayList<>());
            emptyPage.setTotal(0);
            return emptyPage;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateNegotiationAnnouncement(NegotiationAnnouncementUpdateReqDTO dto) {
        try {
            log.info("开始更新协商公告配置，ID: {}", dto.getId());

            // 1. 根据ID查询现有记录
            ContractNegotiationManagementEntity existingEntity = contractNegotiationManagementMapper.selectById(dto.getId());
            if (existingEntity == null) {
                log.warn("未找到ID为 {} 的协商公告配置记录", dto.getId());
                throw new RuntimeException("协商公告配置不存在");
            }

            log.info("找到现有配置 - 系统租户键: {}", existingEntity.getSysTenantKey());

            // 2. 构建更新条件 - 注意：不更新sysTenantKey字段，保持其不可修改
            LambdaUpdateWrapper<ContractNegotiationManagementEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ContractNegotiationManagementEntity::getId, dto.getId());

            // 3. 设置允许更新的字段
            if (dto.getNegotiationAnnouncementEnabled() != null) {
                updateWrapper.set(ContractNegotiationManagementEntity::getNegotiationAnnouncementEnabled, dto.getNegotiationAnnouncementEnabled());
            }
            if (dto.getNegotiationAnnouncementTextEnabled() != null) {
                updateWrapper.set(ContractNegotiationManagementEntity::getNegotiationAnnouncementTextEnabled, dto.getNegotiationAnnouncementTextEnabled());
            }
            // 协商公告文本内容允许设置为null
            updateWrapper.set(ContractNegotiationManagementEntity::getNegotiationAnnouncementText, dto.getNegotiationAnnouncementText());
            
            // 更新时间
            updateWrapper.set(ContractNegotiationManagementEntity::getUpdatedAt, LocalDateTime.now());

            // 4. 执行更新
            int updateCount = contractNegotiationManagementMapper.update(null, updateWrapper);

            if (updateCount > 0) {
                log.info("成功更新协商公告配置 - ID: {}, 系统租户键: {}, 公告必填启用: {}, 提示文本启用: {}",
                        dto.getId(), 
                        existingEntity.getSysTenantKey(),
                        dto.getNegotiationAnnouncementEnabled(),
                        dto.getNegotiationAnnouncementTextEnabled());
                return true;
            } else {
                log.error("更新协商公告配置失败，ID: {}", dto.getId());
                return false;
            }

        } catch (Exception e) {
            log.error("更新协商公告配置失败，ID: {}", dto.getId(), e);
            throw new RuntimeException("更新协商公告配置失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteNegotiationAnnouncement(NegotiationAnnouncementDeleteReqDTO dto) {
        try {
            log.info("开始删除协商公告配置，ID: {}", dto.getId());

            // 1. 根据ID查询现有记录
            ContractNegotiationManagementEntity existingEntity = contractNegotiationManagementMapper.selectById(dto.getId());
            if (existingEntity == null) {
                log.warn("未找到ID为 {} 的协商公告配置记录", dto.getId());
                throw new RuntimeException("协商公告配置不存在");
            }

            log.info("找到待删除配置 - 系统租户键: {}", existingEntity.getSysTenantKey());

            // 2. 可选：验证权限 - 只允许删除当前用户所属租户的配置
//            UserInfo currentUser = AuthUtil.getCurrentUser();
//            if (currentUser != null && currentUser.getSysTenantKey() != null) {
//                if (!currentUser.getSysTenantKey().equals(existingEntity.getSysTenantKey())) {
//                    log.warn("用户 {} 尝试删除其他租户的协商公告配置，用户租户: {}, 配置租户: {}",
//                            currentUser.getId(), currentUser.getSysTenantKey(), existingEntity.getSysTenantKey());
//                    throw new RuntimeException("无权限删除该协商公告配置");
//                }
//            }

            // 3. 执行删除操作
            int deleteCount = contractNegotiationManagementMapper.deleteById(dto.getId());

            if (deleteCount > 0) {
                log.info("成功删除协商公告配置 - ID: {}, 系统租户键: {}", 
                        dto.getId(), existingEntity.getSysTenantKey());
                return true;
            } else {
                log.error("删除协商公告配置失败，ID: {}", dto.getId());
                return false;
            }

        } catch (Exception e) {
            log.error("删除协商公告配置失败，ID: {}", dto.getId(), e);
            throw new RuntimeException("删除协商公告配置失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createNegotiationAnnouncement(NegotiationAnnouncementCreateReqDTO dto) {
        try {
            log.info("开始创建协商公告配置，系统租户键: {}", dto.getSysTenantKey());

            // 1. 检查该租户是否已存在配置（基于唯一约束）
            ContractNegotiationManagementEntity existingEntity = contractNegotiationManagementMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationManagementEntity>()
                            .eq(ContractNegotiationManagementEntity::getSysTenantKey, dto.getSysTenantKey())
            );

            if (existingEntity != null) {
                log.warn("系统租户键 {} 的协商公告配置已存在，ID: {}", dto.getSysTenantKey(), existingEntity.getId());
                throw new RuntimeException("该租户的协商公告配置已存在，无法重复创建");
            }

            // 2. 创建新的协商公告配置
            ContractNegotiationManagementEntity newEntity = new ContractNegotiationManagementEntity();
            newEntity.setSysTenantKey(dto.getSysTenantKey());
            
            // 设置配置项，如果未传入则使用默认值
            newEntity.setNegotiationAnnouncementEnabled(
                dto.getNegotiationAnnouncementEnabled() != null ? dto.getNegotiationAnnouncementEnabled() : false
            );
            newEntity.setNegotiationAnnouncementTextEnabled(
                dto.getNegotiationAnnouncementTextEnabled() != null ? dto.getNegotiationAnnouncementTextEnabled() : false
            );
            newEntity.setNegotiationAnnouncementText(dto.getNegotiationAnnouncementText());
            
            // 设置时间字段
            LocalDateTime now = LocalDateTime.now();
            newEntity.setCreatedAt(now);
            newEntity.setUpdatedAt(now);

            // 3. 执行插入操作
            int insertCount = contractNegotiationManagementMapper.insert(newEntity);

            if (insertCount > 0) {
                log.info("成功创建协商公告配置 - ID: {}, 系统租户键: {}, 公告必填启用: {}, 提示文本启用: {}",
                        newEntity.getId(),
                        dto.getSysTenantKey(),
                        dto.getNegotiationAnnouncementEnabled(),
                        dto.getNegotiationAnnouncementTextEnabled());
                return true;
            } else {
                log.error("创建协商公告配置失败，系统租户键: {}", dto.getSysTenantKey());
                return false;
            }

        } catch (Exception e) {
            log.error("创建协商公告配置失败，系统租户键: {}", dto.getSysTenantKey(), e);
            throw new RuntimeException("创建协商公告配置失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateNegotiationInstanceAnnouncement(NegotiationInstanceAnnouncementUpdateReqDTO dto) {
        try {
            log.info("开始更新协商实例公告，合同ID: {}", dto.getContractId());

            // 1. 根据合同ID查询协商实例
            ContractNegotiationInstanceEntity existingInstance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, dto.getContractId())
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus, 
                                Arrays.asList(
                                    NegotiationStatusEnum.IN_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.NEGOTIATION_COMPLETE.getCode(),
                                    NegotiationStatusEnum.PENDING_NEGOTIATION.getCode(),
                                    NegotiationStatusEnum.NEGOTIATION_CANCELED.getCode()
                                ))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );
            
            if (existingInstance == null) {
                log.warn("未找到合同ID为 {} 的协商实例", dto.getContractId());
                throw new RuntimeException("该合同的协商实例不存在");
            }

            log.info("找到协商实例 - 实例ID: {}, 当前状态: {}", 
                    existingInstance.getId(), existingInstance.getNegotiationStatus());

            // 2. 执行更新操作
            LambdaUpdateWrapper<ContractNegotiationInstanceEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ContractNegotiationInstanceEntity::getId, existingInstance.getId())
                        .set(ContractNegotiationInstanceEntity::getAnnouncementText, dto.getAnnouncementText())
                        .set(ContractNegotiationInstanceEntity::getUpdatedAt, LocalDateTime.now());

            int updateCount = contractNegotiationInstanceMapper.update(null, updateWrapper);

            if (updateCount > 0) {
                log.info("成功更新协商实例公告 - 合同ID: {}, 实例ID: {}, 公告内容长度: {}", 
                        dto.getContractId(), 
                        existingInstance.getId(),
                        dto.getAnnouncementText() != null ? dto.getAnnouncementText().length() : 0);
                return true;
            } else {
                log.error("更新协商实例公告失败，合同ID: {}", dto.getContractId());
                return false;
            }

        } catch (Exception e) {
            log.error("更新协商实例公告失败，合同ID: {}", dto.getContractId(), e);
            throw new RuntimeException("更新协商实例公告失败：" + e.getMessage());
        }
    }

    @Override
    public List<com.aizuda.boot.modules.system.entity.vo.DepartmentHeadVO> getNegotiationParticipantsByContractId(Long contractId) {
        try {
            log.info("开始查询合同ID: {} 的协商参与人员", contractId);
            
            // 1. 根据contractId查询协商实例
            List<ContractNegotiationInstanceEntity> instances = contractNegotiationInstanceMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
            );
            
            if (instances.isEmpty()) {
                log.warn("未找到合同ID: {} 对应的协商实例", contractId);
                return new ArrayList<>();
            }
            
            // 2. 提取所有instanceId
            List<Integer> instanceIds = instances.stream()
                    .map(ContractNegotiationInstanceEntity::getId)
                    .collect(Collectors.toList());
            
            // 3. 根据instanceId查询所有参与人员
            List<ContractNegotiationParticipantEntity> participants = contractNegotiationParticipantMapper.selectList(
                    new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                            .in(ContractNegotiationParticipantEntity::getInstanceId, instanceIds)
            );
            
            if (participants.isEmpty()) {
                log.warn("未找到合同ID: {} 对应的协商参与人员", contractId);
                return new ArrayList<>();
            }
            
            // 4. 提取所有employeeId并去重
            Set<Long> employeeIds = participants.stream()
                    .map(ContractNegotiationParticipantEntity::getEmployeeId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
            
            if (employeeIds.isEmpty()) {
                log.warn("合同ID: {} 的协商参与人员中没有有效的employeeId", contractId);
                return new ArrayList<>();
            }
            
            // 5. 批量查询用户信息
            List<SysUser> users = sysUserMapper.selectBatchIds(employeeIds);
            
            // 6. 转换为DepartmentHeadVO
            List<com.aizuda.boot.modules.system.entity.vo.DepartmentHeadVO> result = users.stream()
                    .map(user -> {
                        com.aizuda.boot.modules.system.entity.vo.DepartmentHeadVO headVO = 
                                new com.aizuda.boot.modules.system.entity.vo.DepartmentHeadVO();
                        headVO.setHeadId(user.getId());
                        headVO.setHeadName(user.getRealName());
                        return headVO;
                    })
                    .collect(Collectors.toList());
            
            log.info("成功查询到合同ID: {} 的协商参与人员数量: {}", contractId, result.size());
            return result;
            
        } catch (Exception e) {
            log.error("查询合同ID: {} 的协商参与人员失败", contractId, e);
            throw new RuntimeException("查询协商参与人员失败：" + e.getMessage());
        }
    }

}